Collapse SSLPolicy/SSLPolicyBackend into SSLManager
SSLManager, SSLPolicy, and SSLPolicyBackend all pretty much ferry events
from one to the other, without any clear division of responsibility
among them. This CL collapses all the functionality into SSLManager for
clearer code.
BUG=558491
Review-Url: https://codereview.chromium.org/2395663002
Cr-Commit-Position: refs/heads/master@{#423240}
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 810050d..03a523a 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -1274,10 +1274,6 @@
"ssl/ssl_error_handler.h",
"ssl/ssl_manager.cc",
"ssl/ssl_manager.h",
- "ssl/ssl_policy.cc",
- "ssl/ssl_policy.h",
- "ssl/ssl_policy_backend.cc",
- "ssl/ssl_policy_backend.h",
"startup_task_runner.cc",
"startup_task_runner.h",
"storage_partition_impl.cc",
diff --git a/content/browser/loader/DEPS b/content/browser/loader/DEPS
index 929f7ded..1245eec0 100644
--- a/content/browser/loader/DEPS
+++ b/content/browser/loader/DEPS
@@ -233,7 +233,6 @@
"+content/browser/service_worker/service_worker_request_handler.h",
"+content/browser/service_worker/service_worker_response_info.h",
"+content/browser/ssl/ssl_manager.h",
- "+content/browser/ssl/ssl_policy.h",
"+content/public/common/content_client.h",
"+content/public/common/content_switches.h",
"+content/public/common/process_type.h",
diff --git a/content/browser/loader/resource_loader.cc b/content/browser/loader/resource_loader.cc
index 56fd553e..1993da2 100644
--- a/content/browser/loader/resource_loader.cc
+++ b/content/browser/loader/resource_loader.cc
@@ -24,7 +24,6 @@
#include "content/browser/service_worker/service_worker_response_info.h"
#include "content/browser/ssl/ssl_client_auth_handler.h"
#include "content/browser/ssl/ssl_manager.h"
-#include "content/browser/ssl/ssl_policy.h"
#include "content/public/browser/resource_dispatcher_host_login_delegate.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_switches.h"
diff --git a/content/browser/ssl/ssl_manager.cc b/content/browser/ssl/ssl_manager.cc
index 2ff7205..bc38ee4 100644
--- a/content/browser/ssl/ssl_manager.cc
+++ b/content/browser/ssl/ssl_manager.cc
@@ -8,18 +8,21 @@
#include "base/bind.h"
#include "base/macros.h"
+#include "base/metrics/histogram_macros.h"
#include "base/strings/utf_string_conversions.h"
#include "base/supports_user_data.h"
#include "content/browser/frame_host/navigation_entry_impl.h"
#include "content/browser/loader/resource_dispatcher_host_impl.h"
#include "content/browser/loader/resource_request_info_impl.h"
#include "content/browser/ssl/ssl_error_handler.h"
-#include "content/browser/ssl/ssl_policy.h"
#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/common/security_style_util.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/certificate_request_result_type.h"
+#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/navigation_details.h"
-#include "content/public/browser/resource_request_details.h"
+#include "content/public/browser/ssl_host_state_delegate.h"
#include "content/public/browser/ssl_status.h"
#include "net/url_request/url_request.h"
@@ -29,6 +32,45 @@
const char kSSLManagerKeyName[] = "content_ssl_manager";
+// Events for UMA. Do not reorder or change!
+enum SSLGoodCertSeenEvent {
+ NO_PREVIOUS_EXCEPTION = 0,
+ HAD_PREVIOUS_EXCEPTION = 1,
+ SSL_GOOD_CERT_SEEN_EVENT_MAX = 2
+};
+
+void OnAllowCertificate(SSLErrorHandler* handler,
+ SSLHostStateDelegate* state_delegate,
+ CertificateRequestResultType decision) {
+ DCHECK(handler->ssl_info().is_valid());
+ switch (decision) {
+ case CERTIFICATE_REQUEST_RESULT_TYPE_CONTINUE:
+ // Note that we should not call SetMaxSecurityStyle here, because
+ // the active NavigationEntry has just been deleted (in
+ // HideInterstitialPage) and the new NavigationEntry will not be
+ // set until DidNavigate. This is ok, because the new
+ // NavigationEntry will have its max security style set within
+ // DidNavigate.
+ //
+ // While AllowCert() executes synchronously on this thread,
+ // ContinueRequest() gets posted to a different thread. Calling
+ // AllowCert() first ensures deterministic ordering.
+ if (state_delegate) {
+ state_delegate->AllowCert(handler->request_url().host(),
+ *handler->ssl_info().cert.get(),
+ handler->cert_error());
+ }
+ handler->ContinueRequest();
+ return;
+ case CERTIFICATE_REQUEST_RESULT_TYPE_DENY:
+ handler->DenyRequest();
+ return;
+ case CERTIFICATE_REQUEST_RESULT_TYPE_CANCEL:
+ handler->CancelRequest();
+ return;
+ }
+}
+
class SSLManagerSet : public base::SupportsUserData::Data {
public:
SSLManagerSet() {
@@ -68,7 +110,7 @@
SSLManager* manager =
static_cast<NavigationControllerImpl*>(&web_contents->GetController())
->ssl_manager();
- manager->policy()->OnCertError(std::move(handler));
+ manager->OnCertError(std::move(handler));
}
} // namespace
@@ -122,9 +164,9 @@
}
SSLManager::SSLManager(NavigationControllerImpl* controller)
- : backend_(controller),
- policy_(new SSLPolicy(&backend_)),
- controller_(controller) {
+ : controller_(controller),
+ ssl_host_state_delegate_(
+ controller->GetBrowserContext()->GetSSLHostStateDelegate()) {
DCHECK(controller_);
SSLManagerSet* managers = static_cast<SSLManagerSet*>(
@@ -144,40 +186,154 @@
void SSLManager::DidCommitProvisionalLoad(const LoadCommittedDetails& details) {
NavigationEntryImpl* entry = controller_->GetLastCommittedEntry();
- policy()->UpdateEntry(entry, controller_->delegate()->GetWebContents());
+ UpdateEntry(entry);
// Always notify the WebContents that the SSL state changed when a
// load is committed, in case the active navigation entry has changed.
NotifyDidChangeVisibleSSLState();
}
void SSLManager::DidRunInsecureContent(const GURL& security_origin) {
- NavigationEntryImpl* navigation_entry = controller_->GetLastCommittedEntry();
- policy()->DidRunInsecureContent(navigation_entry, security_origin);
- UpdateEntry(navigation_entry);
+ NavigationEntryImpl* entry = controller_->GetLastCommittedEntry();
+ if (!entry)
+ return;
+
+ SiteInstance* site_instance = entry->site_instance();
+ if (!site_instance)
+ return;
+
+ if (ssl_host_state_delegate_) {
+ ssl_host_state_delegate_->HostRanInsecureContent(
+ security_origin.host(), site_instance->GetProcess()->GetID(),
+ SSLHostStateDelegate::MIXED_CONTENT);
+ }
+ UpdateEntry(entry);
+ NotifySSLInternalStateChanged(controller_->GetBrowserContext());
}
void SSLManager::DidRunContentWithCertErrors(const GURL& security_origin) {
- NavigationEntryImpl* navigation_entry = controller_->GetLastCommittedEntry();
- policy()->DidRunContentWithCertErrors(navigation_entry, security_origin);
- UpdateEntry(navigation_entry);
+ NavigationEntryImpl* entry = controller_->GetLastCommittedEntry();
+ if (!entry)
+ return;
+
+ SiteInstance* site_instance = entry->site_instance();
+ if (!site_instance)
+ return;
+
+ if (ssl_host_state_delegate_) {
+ ssl_host_state_delegate_->HostRanInsecureContent(
+ security_origin.host(), site_instance->GetProcess()->GetID(),
+ SSLHostStateDelegate::CERT_ERRORS_CONTENT);
+ }
+ UpdateEntry(entry);
+ NotifySSLInternalStateChanged(controller_->GetBrowserContext());
}
-void SSLManager::DidStartResourceResponse(
- const ResourceRequestDetails& details) {
- // Notify our policy that we started a resource request. Ideally, the
- // policy should have the ability to cancel the request, but we can't do
- // that yet.
- policy()->OnRequestStarted(details.url, details.has_certificate,
- details.ssl_cert_status);
+void SSLManager::OnCertError(std::unique_ptr<SSLErrorHandler> handler) {
+ bool expired_previous_decision = false;
+ // First we check if we know the policy for this error.
+ DCHECK(handler->ssl_info().is_valid());
+ SSLHostStateDelegate::CertJudgment judgment =
+ ssl_host_state_delegate_
+ ? ssl_host_state_delegate_->QueryPolicy(
+ handler->request_url().host(), *handler->ssl_info().cert.get(),
+ handler->cert_error(), &expired_previous_decision)
+ : SSLHostStateDelegate::DENIED;
+
+ if (judgment == SSLHostStateDelegate::ALLOWED) {
+ handler->ContinueRequest();
+ return;
+ }
+
+ // For all other hosts, which must be DENIED, a blocking page is shown to the
+ // user every time they come back to the page.
+ int options_mask = 0;
+ switch (handler->cert_error()) {
+ case net::ERR_CERT_COMMON_NAME_INVALID:
+ case net::ERR_CERT_DATE_INVALID:
+ case net::ERR_CERT_AUTHORITY_INVALID:
+ case net::ERR_CERT_WEAK_SIGNATURE_ALGORITHM:
+ case net::ERR_CERT_WEAK_KEY:
+ case net::ERR_CERT_NAME_CONSTRAINT_VIOLATION:
+ case net::ERR_CERT_VALIDITY_TOO_LONG:
+ case net::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED:
+ if (!handler->fatal())
+ options_mask |= OVERRIDABLE;
+ else
+ options_mask |= STRICT_ENFORCEMENT;
+ if (expired_previous_decision)
+ options_mask |= EXPIRED_PREVIOUS_DECISION;
+ OnCertErrorInternal(std::move(handler), options_mask);
+ break;
+ case net::ERR_CERT_NO_REVOCATION_MECHANISM:
+ // Ignore this error.
+ handler->ContinueRequest();
+ break;
+ case net::ERR_CERT_UNABLE_TO_CHECK_REVOCATION:
+ // We ignore this error but will show a warning status in the location
+ // bar.
+ handler->ContinueRequest();
+ break;
+ case net::ERR_CERT_CONTAINS_ERRORS:
+ case net::ERR_CERT_REVOKED:
+ case net::ERR_CERT_INVALID:
+ case net::ERR_SSL_WEAK_SERVER_EPHEMERAL_DH_KEY:
+ case net::ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN:
+ if (handler->fatal())
+ options_mask |= STRICT_ENFORCEMENT;
+ if (expired_previous_decision)
+ options_mask |= EXPIRED_PREVIOUS_DECISION;
+ OnCertErrorInternal(std::move(handler), options_mask);
+ break;
+ default:
+ NOTREACHED();
+ handler->CancelRequest();
+ break;
+ }
}
-void SSLManager::DidReceiveResourceRedirect(
- const ResourceRedirectDetails& details) {
- // TODO(abarth): Make sure our redirect behavior is correct. If we ever see a
- // non-HTTPS resource in the redirect chain, we want to trigger
- // insecure content, even if the redirect chain goes back to
- // HTTPS. This is because the network attacker can redirect the
- // HTTP request to https://attacker.com/payload.js.
+void SSLManager::DidStartResourceResponse(const GURL& url,
+ bool has_certificate,
+ net::CertStatus ssl_cert_status) {
+ if (has_certificate && url.SchemeIsCryptographic() &&
+ !net::IsCertStatusError(ssl_cert_status)) {
+ // If the scheme is https: or wss: *and* the security info for the
+ // cert has been set (i.e. the cert id is not 0) and the cert did
+ // not have any errors, revoke any previous decisions that
+ // have occurred. If the cert info has not been set, do nothing since it
+ // isn't known if the connection was actually a valid connection or if it
+ // had a cert error.
+ SSLGoodCertSeenEvent event = NO_PREVIOUS_EXCEPTION;
+ if (ssl_host_state_delegate_ &&
+ ssl_host_state_delegate_->HasAllowException(url.host())) {
+ // If there's no certificate error, a good certificate has been seen, so
+ // clear out any exceptions that were made by the user for bad
+ // certificates. This intentionally does not apply to cached resources
+ // (see https://crbug.com/634553 for an explanation).
+ ssl_host_state_delegate_->RevokeUserAllowExceptions(url.host());
+ event = HAD_PREVIOUS_EXCEPTION;
+ }
+ UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.good_cert_seen", event,
+ SSL_GOOD_CERT_SEEN_EVENT_MAX);
+ }
+}
+
+void SSLManager::OnCertErrorInternal(std::unique_ptr<SSLErrorHandler> handler,
+ int options_mask) {
+ bool overridable = (options_mask & OVERRIDABLE) != 0;
+ bool strict_enforcement = (options_mask & STRICT_ENFORCEMENT) != 0;
+ bool expired_previous_decision =
+ (options_mask & EXPIRED_PREVIOUS_DECISION) != 0;
+
+ WebContents* web_contents = handler->web_contents();
+ int cert_error = handler->cert_error();
+ const net::SSLInfo& ssl_info = handler->ssl_info();
+ const GURL& request_url = handler->request_url();
+ ResourceType resource_type = handler->resource_type();
+ GetContentClient()->browser()->AllowCertificateError(
+ web_contents, cert_error, ssl_info, request_url, resource_type,
+ overridable, strict_enforcement, expired_previous_decision,
+ base::Bind(&OnAllowCertificate, base::Owned(handler.release()),
+ ssl_host_state_delegate_));
}
void SSLManager::UpdateEntry(NavigationEntryImpl* entry) {
@@ -188,7 +344,49 @@
SSLStatus original_ssl_status = entry->GetSSL(); // Copy!
- policy()->UpdateEntry(entry, controller_->delegate()->GetWebContents());
+ // Initialize the entry with an initial SecurityStyle if needed.
+ if (entry->GetSSL().security_style == SECURITY_STYLE_UNKNOWN) {
+ entry->GetSSL().security_style = GetSecurityStyleForResource(
+ entry->GetURL(), !!entry->GetSSL().certificate,
+ entry->GetSSL().cert_status);
+ }
+
+ WebContentsImpl* web_contents_impl =
+ static_cast<WebContentsImpl*>(controller_->delegate()->GetWebContents());
+ if (entry->GetSSL().security_style == SECURITY_STYLE_UNAUTHENTICATED)
+ return;
+
+ // Update the entry's flags for insecure content.
+ if (!web_contents_impl->DisplayedInsecureContent())
+ entry->GetSSL().content_status &= ~SSLStatus::DISPLAYED_INSECURE_CONTENT;
+ if (web_contents_impl->DisplayedInsecureContent())
+ entry->GetSSL().content_status |= SSLStatus::DISPLAYED_INSECURE_CONTENT;
+ if (!web_contents_impl->DisplayedContentWithCertErrors())
+ entry->GetSSL().content_status &=
+ ~SSLStatus::DISPLAYED_CONTENT_WITH_CERT_ERRORS;
+ if (web_contents_impl->DisplayedContentWithCertErrors())
+ entry->GetSSL().content_status |=
+ SSLStatus::DISPLAYED_CONTENT_WITH_CERT_ERRORS;
+
+ SiteInstance* site_instance = entry->site_instance();
+ // Note that |site_instance| can be NULL here because NavigationEntries don't
+ // necessarily have site instances. Without a process, the entry can't
+ // possibly have insecure content. See bug http://crbug.com/12423.
+ if (site_instance && ssl_host_state_delegate_ &&
+ ssl_host_state_delegate_->DidHostRunInsecureContent(
+ entry->GetURL().host(), site_instance->GetProcess()->GetID(),
+ SSLHostStateDelegate::MIXED_CONTENT)) {
+ entry->GetSSL().security_style = SECURITY_STYLE_AUTHENTICATION_BROKEN;
+ entry->GetSSL().content_status |= SSLStatus::RAN_INSECURE_CONTENT;
+ }
+
+ if (site_instance && ssl_host_state_delegate_ &&
+ ssl_host_state_delegate_->DidHostRunInsecureContent(
+ entry->GetURL().host(), site_instance->GetProcess()->GetID(),
+ SSLHostStateDelegate::CERT_ERRORS_CONTENT)) {
+ entry->GetSSL().security_style = SECURITY_STYLE_AUTHENTICATION_BROKEN;
+ entry->GetSSL().content_status |= SSLStatus::RAN_CONTENT_WITH_CERT_ERRORS;
+ }
if (!entry->GetSSL().Equals(original_ssl_status))
NotifyDidChangeVisibleSSLState();
diff --git a/content/browser/ssl/ssl_manager.h b/content/browser/ssl/ssl_manager.h
index 493d0ba..99d9845c 100644
--- a/content/browser/ssl/ssl_manager.h
+++ b/content/browser/ssl/ssl_manager.h
@@ -11,7 +11,6 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "content/browser/ssl/ssl_error_handler.h"
-#include "content/browser/ssl/ssl_policy_backend.h"
#include "content/common/content_export.h"
#include "content/public/browser/global_request_id.h"
#include "net/base/net_errors.h"
@@ -26,19 +25,16 @@
class BrowserContext;
class NavigationEntryImpl;
class NavigationControllerImpl;
-class SSLPolicy;
+class SSLHostStateDelegate;
struct LoadCommittedDetails;
-struct ResourceRedirectDetails;
-struct ResourceRequestDetails;
-// The SSLManager SSLManager controls the SSL UI elements in a WebContents. It
+// The SSLManager controls the SSL UI elements in a WebContents. It
// listens for various events that influence when these elements should or
// should not be displayed and adjusts them accordingly.
//
// There is one SSLManager per tab.
// The security state (secure/insecure) is stored in the navigation entry.
// Along with it are stored any SSL error code and the associated cert.
-
class CONTENT_EXPORT SSLManager {
public:
// Entry point for SSLCertificateErrors. This function begins the process
@@ -70,20 +66,17 @@
static void NotifySSLInternalStateChanged(BrowserContext* context);
// Construct an SSLManager for the specified tab.
- // If |delegate| is NULL, SSLPolicy::GetDefaultPolicy() is used.
explicit SSLManager(NavigationControllerImpl* controller);
virtual ~SSLManager();
- SSLPolicy* policy() { return policy_.get(); }
- SSLPolicyBackend* backend() { return &backend_; }
-
// The navigation controller associated with this SSLManager. The
// NavigationController is guaranteed to outlive the SSLManager.
NavigationControllerImpl* controller() { return controller_; }
void DidCommitProvisionalLoad(const LoadCommittedDetails& details);
- void DidStartResourceResponse(const ResourceRequestDetails& details);
- void DidReceiveResourceRedirect(const ResourceRedirectDetails& details);
+ void DidStartResourceResponse(const GURL& url,
+ bool has_certificate,
+ net::CertStatus ssl_cert_status);
// Entry point for insecure mixed content (loaded over HTTP).
void DidRunInsecureContent(const GURL& security_origin);
@@ -91,7 +84,29 @@
// Entry point for content loaded with HTTPS certificate errors.
void DidRunContentWithCertErrors(const GURL& security_origin);
+ // An error occurred with the certificate in an SSL connection.
+ void OnCertError(std::unique_ptr<SSLErrorHandler> handler);
+
private:
+ enum OnCertErrorInternalOptionsMask {
+ OVERRIDABLE = 1 << 0,
+ STRICT_ENFORCEMENT = 1 << 1,
+ EXPIRED_PREVIOUS_DECISION = 1 << 2
+ };
+
+ // Helper method for handling certificate errors.
+ //
+ // Options should be a bitmask combination of OnCertErrorInternalOptionsMask.
+ // OVERRIDABLE indicates whether or not the user could (assuming perfect
+ // knowledge) successfully override the error and still get the security
+ // guarantees of TLS. STRICT_ENFORCEMENT indicates whether or not the site the
+ // user is trying to connect to has requested strict enforcement of
+ // certificate validation (e.g. with HTTP Strict-Transport-Security).
+ // EXPIRED_PREVIOUS_DECISION indicates whether a user decision had been
+ // previously made but the decision has expired.
+ void OnCertErrorInternal(std::unique_ptr<SSLErrorHandler> handler,
+ int options_mask);
+
// Updates the NavigationEntry with our current state. This will
// notify the WebContents of an SSL state change if a change was
// actually made.
@@ -100,16 +115,13 @@
// Notifies the WebContents that the SSL state changed.
void NotifyDidChangeVisibleSSLState();
- // The backend for the SSLPolicy to actuate its decisions.
- SSLPolicyBackend backend_;
-
- // The SSLPolicy instance for this manager.
- std::unique_ptr<SSLPolicy> policy_;
-
// The NavigationController that owns this SSLManager. We are responsible
// for the security UI of this tab.
NavigationControllerImpl* controller_;
+ // Delegate that manages SSL state specific to each host.
+ SSLHostStateDelegate* ssl_host_state_delegate_;
+
DISALLOW_COPY_AND_ASSIGN(SSLManager);
};
diff --git a/content/browser/ssl/ssl_policy.cc b/content/browser/ssl/ssl_policy.cc
deleted file mode 100644
index fa07378..0000000
--- a/content/browser/ssl/ssl_policy.cc
+++ /dev/null
@@ -1,266 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/ssl/ssl_policy.h"
-
-#include "base/base_switches.h"
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/memory/singleton.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/strings/string_piece.h"
-#include "base/strings/string_util.h"
-#include "content/browser/frame_host/navigation_entry_impl.h"
-#include "content/browser/renderer_host/render_process_host_impl.h"
-#include "content/browser/renderer_host/render_view_host_impl.h"
-#include "content/browser/site_instance_impl.h"
-#include "content/browser/ssl/ssl_error_handler.h"
-#include "content/browser/web_contents/web_contents_impl.h"
-#include "content/common/security_style_util.h"
-#include "content/public/browser/content_browser_client.h"
-#include "content/public/browser/ssl_status.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/common/resource_type.h"
-#include "content/public/common/url_constants.h"
-#include "net/ssl/ssl_info.h"
-#include "url/gurl.h"
-
-namespace content {
-
-namespace {
-
-// Events for UMA. Do not reorder or change!
-enum SSLGoodCertSeenEvent {
- NO_PREVIOUS_EXCEPTION = 0,
- HAD_PREVIOUS_EXCEPTION = 1,
- SSL_GOOD_CERT_SEEN_EVENT_MAX = 2
-};
-
-void OnAllowCertificate(SSLErrorHandler* handler,
- const SSLPolicy* const policy,
- CertificateRequestResultType decision) {
- DCHECK(handler->ssl_info().is_valid());
- switch (decision) {
- case CERTIFICATE_REQUEST_RESULT_TYPE_CONTINUE:
- // Note that we should not call SetMaxSecurityStyle here, because
- // the active NavigationEntry has just been deleted (in
- // HideInterstitialPage) and the new NavigationEntry will not be
- // set until DidNavigate. This is ok, because the new
- // NavigationEntry will have its max security style set within
- // DidNavigate.
- //
- // While AllowCertForHost() executes synchronously on this thread,
- // ContinueRequest() gets posted to a different thread. Calling
- // AllowCertForHost() first ensures deterministic ordering.
- policy->backend()->AllowCertForHost(*handler->ssl_info().cert.get(),
- handler->request_url().host(),
- handler->cert_error());
- handler->ContinueRequest();
- return;
- case CERTIFICATE_REQUEST_RESULT_TYPE_DENY:
- handler->DenyRequest();
- return;
- case CERTIFICATE_REQUEST_RESULT_TYPE_CANCEL:
- handler->CancelRequest();
- return;
- }
-}
-
-} // namespace
-
-SSLPolicy::SSLPolicy(SSLPolicyBackend* backend)
- : backend_(backend) {
- DCHECK(backend_);
-}
-
-void SSLPolicy::OnCertError(std::unique_ptr<SSLErrorHandler> handler) {
- bool expired_previous_decision = false;
- // First we check if we know the policy for this error.
- DCHECK(handler->ssl_info().is_valid());
- SSLHostStateDelegate::CertJudgment judgment =
- backend_->QueryPolicy(*handler->ssl_info().cert.get(),
- handler->request_url().host(),
- handler->cert_error(),
- &expired_previous_decision);
-
- if (judgment == SSLHostStateDelegate::ALLOWED) {
- handler->ContinueRequest();
- return;
- }
-
- // For all other hosts, which must be DENIED, a blocking page is shown to the
- // user every time they come back to the page.
- int options_mask = 0;
- switch (handler->cert_error()) {
- case net::ERR_CERT_COMMON_NAME_INVALID:
- case net::ERR_CERT_DATE_INVALID:
- case net::ERR_CERT_AUTHORITY_INVALID:
- case net::ERR_CERT_WEAK_SIGNATURE_ALGORITHM:
- case net::ERR_CERT_WEAK_KEY:
- case net::ERR_CERT_NAME_CONSTRAINT_VIOLATION:
- case net::ERR_CERT_VALIDITY_TOO_LONG:
- case net::ERR_CERTIFICATE_TRANSPARENCY_REQUIRED:
- if (!handler->fatal())
- options_mask |= OVERRIDABLE;
- else
- options_mask |= STRICT_ENFORCEMENT;
- if (expired_previous_decision)
- options_mask |= EXPIRED_PREVIOUS_DECISION;
- OnCertErrorInternal(std::move(handler), options_mask);
- break;
- case net::ERR_CERT_NO_REVOCATION_MECHANISM:
- // Ignore this error.
- handler->ContinueRequest();
- break;
- case net::ERR_CERT_UNABLE_TO_CHECK_REVOCATION:
- // We ignore this error but will show a warning status in the location
- // bar.
- handler->ContinueRequest();
- break;
- case net::ERR_CERT_CONTAINS_ERRORS:
- case net::ERR_CERT_REVOKED:
- case net::ERR_CERT_INVALID:
- case net::ERR_SSL_WEAK_SERVER_EPHEMERAL_DH_KEY:
- case net::ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN:
- if (handler->fatal())
- options_mask |= STRICT_ENFORCEMENT;
- if (expired_previous_decision)
- options_mask |= EXPIRED_PREVIOUS_DECISION;
- OnCertErrorInternal(std::move(handler), options_mask);
- break;
- default:
- NOTREACHED();
- handler->CancelRequest();
- break;
- }
-}
-
-void SSLPolicy::DidRunInsecureContent(NavigationEntryImpl* entry,
- const GURL& security_origin) {
- if (!entry)
- return;
-
- SiteInstance* site_instance = entry->site_instance();
- if (!site_instance)
- return;
-
- backend_->HostRanInsecureContent(security_origin.host(),
- site_instance->GetProcess()->GetID());
-}
-
-void SSLPolicy::DidRunContentWithCertErrors(NavigationEntryImpl* entry,
- const GURL& security_origin) {
- if (!entry)
- return;
-
- SiteInstance* site_instance = entry->site_instance();
- if (!site_instance)
- return;
-
- backend_->HostRanContentWithCertErrors(security_origin.host(),
- site_instance->GetProcess()->GetID());
-}
-
-void SSLPolicy::OnRequestStarted(const GURL& url,
- bool has_certificate,
- net::CertStatus cert_status) {
- if (has_certificate && url.SchemeIsCryptographic() &&
- !net::IsCertStatusError(cert_status)) {
- // If the scheme is https: or wss: *and* the security info for the
- // cert has been set (i.e. the cert id is not 0) and the cert did
- // not have any errors, revoke any previous decisions that
- // have occurred. If the cert info has not been set, do nothing since it
- // isn't known if the connection was actually a valid connection or if it
- // had a cert error.
- SSLGoodCertSeenEvent event = NO_PREVIOUS_EXCEPTION;
- if (backend_->HasAllowException(url.host())) {
- // If there's no certificate error, a good certificate has been seen, so
- // clear out any exceptions that were made by the user for bad
- // certificates. This intentionally does not apply to cached resources
- // (see https://crbug.com/634553 for an explanation).
- backend_->RevokeUserAllowExceptions(url.host());
- event = HAD_PREVIOUS_EXCEPTION;
- }
- UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.good_cert_seen", event,
- SSL_GOOD_CERT_SEEN_EVENT_MAX);
- }
-}
-
-void SSLPolicy::UpdateEntry(NavigationEntryImpl* entry,
- WebContents* web_contents) {
- DCHECK(entry);
-
- WebContentsImpl* web_contents_impl =
- static_cast<WebContentsImpl*>(web_contents);
-
- InitializeEntryIfNeeded(entry);
-
- if (entry->GetSSL().security_style == SECURITY_STYLE_UNAUTHENTICATED)
- return;
-
- if (!web_contents_impl->DisplayedInsecureContent())
- entry->GetSSL().content_status &= ~SSLStatus::DISPLAYED_INSECURE_CONTENT;
-
- if (web_contents_impl->DisplayedInsecureContent())
- entry->GetSSL().content_status |= SSLStatus::DISPLAYED_INSECURE_CONTENT;
-
- if (!web_contents_impl->DisplayedContentWithCertErrors())
- entry->GetSSL().content_status &=
- ~SSLStatus::DISPLAYED_CONTENT_WITH_CERT_ERRORS;
-
- if (web_contents_impl->DisplayedContentWithCertErrors())
- entry->GetSSL().content_status |=
- SSLStatus::DISPLAYED_CONTENT_WITH_CERT_ERRORS;
-
- SiteInstance* site_instance = entry->site_instance();
- // Note that |site_instance| can be NULL here because NavigationEntries don't
- // necessarily have site instances. Without a process, the entry can't
- // possibly have insecure content. See bug http://crbug.com/12423.
- if (site_instance &&
- backend_->DidHostRunInsecureContent(
- entry->GetURL().host(), site_instance->GetProcess()->GetID())) {
- entry->GetSSL().security_style =
- SECURITY_STYLE_AUTHENTICATION_BROKEN;
- entry->GetSSL().content_status |= SSLStatus::RAN_INSECURE_CONTENT;
- }
-
- if (site_instance &&
- backend_->DidHostRunContentWithCertErrors(
- entry->GetURL().host(), site_instance->GetProcess()->GetID())) {
- entry->GetSSL().security_style = SECURITY_STYLE_AUTHENTICATION_BROKEN;
- entry->GetSSL().content_status |= SSLStatus::RAN_CONTENT_WITH_CERT_ERRORS;
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Certificate Error Routines
-
-void SSLPolicy::OnCertErrorInternal(std::unique_ptr<SSLErrorHandler> handler,
- int options_mask) {
- bool overridable = (options_mask & OVERRIDABLE) != 0;
- bool strict_enforcement = (options_mask & STRICT_ENFORCEMENT) != 0;
- bool expired_previous_decision =
- (options_mask & EXPIRED_PREVIOUS_DECISION) != 0;
-
- WebContents* web_contents = handler->web_contents();
- int cert_error = handler->cert_error();
- const net::SSLInfo& ssl_info = handler->ssl_info();
- const GURL& request_url = handler->request_url();
- ResourceType resource_type = handler->resource_type();
- GetContentClient()->browser()->AllowCertificateError(
- web_contents, cert_error, ssl_info, request_url, resource_type,
- overridable, strict_enforcement, expired_previous_decision,
- base::Bind(&OnAllowCertificate, base::Owned(handler.release()), this));
-}
-
-void SSLPolicy::InitializeEntryIfNeeded(NavigationEntryImpl* entry) {
- if (entry->GetSSL().security_style != SECURITY_STYLE_UNKNOWN)
- return;
-
- entry->GetSSL().security_style = GetSecurityStyleForResource(
- entry->GetURL(), !!entry->GetSSL().certificate,
- entry->GetSSL().cert_status);
-}
-
-} // namespace content
diff --git a/content/browser/ssl/ssl_policy.h b/content/browser/ssl/ssl_policy.h
deleted file mode 100644
index f7c0496..0000000
--- a/content/browser/ssl/ssl_policy.h
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_SSL_SSL_POLICY_H_
-#define CONTENT_BROWSER_SSL_SSL_POLICY_H_
-
-#include <string>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "content/common/content_export.h"
-#include "content/public/browser/certificate_request_result_type.h"
-#include "content/public/common/resource_type.h"
-#include "net/cert/cert_status_flags.h"
-
-class GURL;
-
-namespace content {
-class NavigationEntryImpl;
-class SSLErrorHandler;
-class SSLPolicyBackend;
-class WebContents;
-
-// SSLPolicy
-//
-// This class is responsible for making the security decisions that concern the
-// SSL trust indicators. It relies on the SSLPolicyBackend to actually enact
-// the decisions it reaches.
-//
-class CONTENT_EXPORT SSLPolicy {
- public:
- explicit SSLPolicy(SSLPolicyBackend* backend);
-
- // An error occurred with the certificate in an SSL connection.
- void OnCertError(std::unique_ptr<SSLErrorHandler> handler);
-
- void DidRunInsecureContent(NavigationEntryImpl* entry,
- const GURL& security_origin);
-
- void DidRunContentWithCertErrors(NavigationEntryImpl* entry,
- const GURL& security_origin);
-
- // We have started a resource request for |url| and if it has a certificate
- // and |cert_status|.
- void OnRequestStarted(const GURL& url,
- bool has_certificate,
- net::CertStatus cert_status);
-
- // Update the SSL information in |entry| to match the current state.
- // |web_contents| is the WebContents associated with this entry.
- void UpdateEntry(NavigationEntryImpl* entry, WebContents* web_contents);
-
- SSLPolicyBackend* backend() const { return backend_; }
-
- private:
- enum OnCertErrorInternalOptionsMask {
- OVERRIDABLE = 1 << 0,
- STRICT_ENFORCEMENT = 1 << 1,
- EXPIRED_PREVIOUS_DECISION = 1 << 2
- };
-
- // Helper method for derived classes handling certificate errors.
- //
- // Options should be a bitmask combination of OnCertErrorInternalOptionsMask.
- // OVERRIDABLE indicates whether or not the user could (assuming perfect
- // knowledge) successfully override the error and still get the security
- // guarantees of TLS. STRICT_ENFORCEMENT indicates whether or not the site the
- // user is trying to connect to has requested strict enforcement of
- // certificate validation (e.g. with HTTP Strict-Transport-Security).
- // EXPIRED_PREVIOUS_DECISION indicates whether a user decision had been
- // previously made but the decision has expired.
- void OnCertErrorInternal(std::unique_ptr<SSLErrorHandler> handler,
- int options_mask);
-
- // If the security style of |entry| has not been initialized, then initialize
- // it with the default style for its URL.
- void InitializeEntryIfNeeded(NavigationEntryImpl* entry);
-
- // The backend we use to enact our decisions.
- SSLPolicyBackend* backend_;
-
- DISALLOW_COPY_AND_ASSIGN(SSLPolicy);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_SSL_SSL_POLICY_H_
diff --git a/content/browser/ssl/ssl_policy_backend.cc b/content/browser/ssl/ssl_policy_backend.cc
deleted file mode 100644
index 34fa2e4b..0000000
--- a/content/browser/ssl/ssl_policy_backend.cc
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/ssl/ssl_policy_backend.h"
-
-#include "content/browser/frame_host/navigation_controller_impl.h"
-#include "content/public/browser/browser_context.h"
-#include "content/public/browser/ssl_host_state_delegate.h"
-
-namespace content {
-
-SSLPolicyBackend::SSLPolicyBackend(NavigationControllerImpl* controller)
- : ssl_host_state_delegate_(
- controller->GetBrowserContext()->GetSSLHostStateDelegate()),
- controller_(controller) {
- DCHECK(controller_);
-}
-
-void SSLPolicyBackend::HostRanInsecureContent(const std::string& host, int id) {
- if (ssl_host_state_delegate_)
- ssl_host_state_delegate_->HostRanInsecureContent(
- host, id, SSLHostStateDelegate::MIXED_CONTENT);
- SSLManager::NotifySSLInternalStateChanged(controller_->GetBrowserContext());
-}
-
-bool SSLPolicyBackend::DidHostRunInsecureContent(const std::string& host,
- int pid) const {
- if (!ssl_host_state_delegate_)
- return false;
-
- return ssl_host_state_delegate_->DidHostRunInsecureContent(
- host, pid, SSLHostStateDelegate::MIXED_CONTENT);
-}
-
-void SSLPolicyBackend::HostRanContentWithCertErrors(const std::string& host,
- int id) {
- if (ssl_host_state_delegate_)
- ssl_host_state_delegate_->HostRanInsecureContent(
- host, id, SSLHostStateDelegate::CERT_ERRORS_CONTENT);
- SSLManager::NotifySSLInternalStateChanged(controller_->GetBrowserContext());
-}
-
-bool SSLPolicyBackend::DidHostRunContentWithCertErrors(const std::string& host,
- int pid) const {
- if (!ssl_host_state_delegate_)
- return false;
-
- return ssl_host_state_delegate_->DidHostRunInsecureContent(
- host, pid, SSLHostStateDelegate::CERT_ERRORS_CONTENT);
-}
-
-void SSLPolicyBackend::RevokeUserAllowExceptions(const std::string& host) {
- if (!ssl_host_state_delegate_)
- return;
-
- ssl_host_state_delegate_->RevokeUserAllowExceptions(host);
-}
-
-bool SSLPolicyBackend::HasAllowException(const std::string& host) {
- if (!ssl_host_state_delegate_)
- return false;
-
- return ssl_host_state_delegate_->HasAllowException(host);
-}
-
-void SSLPolicyBackend::AllowCertForHost(const net::X509Certificate& cert,
- const std::string& host,
- net::CertStatus error) {
- if (ssl_host_state_delegate_)
- ssl_host_state_delegate_->AllowCert(host, cert, error);
-}
-
-SSLHostStateDelegate::CertJudgment SSLPolicyBackend::QueryPolicy(
- const net::X509Certificate& cert,
- const std::string& host,
- net::CertStatus error,
- bool* expired_previous_decision) {
- return ssl_host_state_delegate_ ?
- ssl_host_state_delegate_->QueryPolicy(
- host, cert, error, expired_previous_decision) :
- SSLHostStateDelegate::DENIED;
-}
-
-} // namespace content
diff --git a/content/browser/ssl/ssl_policy_backend.h b/content/browser/ssl/ssl_policy_backend.h
deleted file mode 100644
index 84c38af4..0000000
--- a/content/browser/ssl/ssl_policy_backend.h
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_SSL_SSL_POLICY_BACKEND_H_
-#define CONTENT_BROWSER_SSL_SSL_POLICY_BACKEND_H_
-
-#include <string>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/strings/string16.h"
-#include "content/public/browser/ssl_host_state_delegate.h"
-#include "net/cert/cert_status_flags.h"
-#include "net/cert/x509_certificate.h"
-
-namespace content {
-class NavigationControllerImpl;
-
-class CONTENT_EXPORT SSLPolicyBackend {
- public:
- explicit SSLPolicyBackend(NavigationControllerImpl* controller);
-
- // Records that a host has run mixed content loaded over HTTP.
- void HostRanInsecureContent(const std::string& host, int pid);
-
- // Returns whether the specified host ran insecure content loaded over HTTP.
- bool DidHostRunInsecureContent(const std::string& host, int pid) const;
-
- // Records that a host has run subresources loaded with certificate errors.
- void HostRanContentWithCertErrors(const std::string& host, int pid);
-
- // Returns whether the specified host ran subresources loaded with certificate
- // errors.
- bool DidHostRunContentWithCertErrors(const std::string& host, int pid) const;
-
- // Revokes all allow exceptions by the user for |host|.
- void RevokeUserAllowExceptions(const std::string& host);
-
- // Returns true if and only if a user exception has previously been made for
- // |host|.
- bool HasAllowException(const std::string& host);
-
- // Records that |cert| is permitted to be used for |host| in the future, for
- // a specific error type.
- void AllowCertForHost(const net::X509Certificate& cert,
- const std::string& host,
- net::CertStatus error);
-
- // Queries whether |cert| is allowed for |host|. Returns true in
- // |expired_previous_decision| if a user decision had been made previously but
- // that decision has expired, otherwise false.
- SSLHostStateDelegate::CertJudgment QueryPolicy(
- const net::X509Certificate& cert,
- const std::string& host,
- net::CertStatus error,
- bool* expired_previous_decision);
-
- private:
- // SSL state delegate specific for each host.
- SSLHostStateDelegate* ssl_host_state_delegate_;
-
- NavigationControllerImpl* controller_;
-
- DISALLOW_COPY_AND_ASSIGN(SSLPolicyBackend);
-};
-
-} // namespace content
-
-#endif // CONTENT_BROWSER_SSL_SSL_POLICY_BACKEND_H_
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index ec95918..081f049 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -2986,7 +2986,8 @@
void WebContentsImpl::DidGetResourceResponseStart(
const ResourceRequestDetails& details) {
- controller_.ssl_manager()->DidStartResourceResponse(details);
+ controller_.ssl_manager()->DidStartResourceResponse(
+ details.url, details.has_certificate, details.ssl_cert_status);
FOR_EACH_OBSERVER(WebContentsObserver, observers_,
DidGetResourceResponseStart(details));
@@ -2994,8 +2995,6 @@
void WebContentsImpl::DidGetRedirectForResourceRequest(
const ResourceRedirectDetails& details) {
- controller_.ssl_manager()->DidReceiveResourceRedirect(details);
-
FOR_EACH_OBSERVER(
WebContentsObserver,
observers_,
diff --git a/content/browser/web_contents/web_contents_impl_unittest.cc b/content/browser/web_contents/web_contents_impl_unittest.cc
index db0f9c2..a3c75914 100644
--- a/content/browser/web_contents/web_contents_impl_unittest.cc
+++ b/content/browser/web_contents/web_contents_impl_unittest.cc
@@ -18,14 +18,15 @@
#include "content/browser/media/media_web_contents_observer.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/site_instance_impl.h"
-#include "content/browser/ssl/ssl_policy.h"
#include "content/browser/webui/content_web_ui_controller_factory.h"
#include "content/browser/webui/web_ui_controller_factory_registry.h"
#include "content/common/frame_messages.h"
#include "content/common/input/synthetic_web_input_event_builders.h"
#include "content/common/media/media_player_delegate_messages.h"
+#include "content/common/security_style_util.h"
#include "content/common/site_isolation_policy.h"
#include "content/common/view_messages.h"
+#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/global_request_id.h"
#include "content/public/browser/interstitial_page_delegate.h"
#include "content/public/browser/javascript_dialog_manager.h"
@@ -33,6 +34,8 @@
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/render_widget_host_view.h"
+#include "content/public/browser/resource_request_details.h"
+#include "content/public/browser/ssl_host_state_delegate.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/browser/web_contents_observer.h"
@@ -3377,16 +3380,17 @@
scoped_refptr<net::X509Certificate> cert =
net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem");
- SSLPolicyBackend* backend = contents()->controller_.ssl_manager()->backend();
const GURL test_url("https://example.test");
- backend->AllowCertForHost(*cert, test_url.host(), 1);
- EXPECT_TRUE(backend->HasAllowException(test_url.host()));
+ SSLHostStateDelegate* state_delegate =
+ contents()->controller_.GetBrowserContext()->GetSSLHostStateDelegate();
+ ASSERT_TRUE(state_delegate);
+ state_delegate->AllowCert(test_url.host(), *cert.get(), 1);
+ EXPECT_TRUE(state_delegate->HasAllowException(test_url.host()));
+ contents()->controller_.ssl_manager()->DidStartResourceResponse(test_url,
+ false, 0);
- contents()->controller_.ssl_manager()->policy()->OnRequestStarted(
- test_url, 0, 0);
-
- EXPECT_TRUE(backend->HasAllowException(test_url.host()));
+ EXPECT_TRUE(state_delegate->HasAllowException(test_url.host()));
DeleteContents();
}
diff --git a/content/public/browser/ssl_host_state_delegate.h b/content/public/browser/ssl_host_state_delegate.h
index 19eedce..fbbe19ae 100644
--- a/content/public/browser/ssl_host_state_delegate.h
+++ b/content/public/browser/ssl_host_state_delegate.h
@@ -33,11 +33,6 @@
};
// The types of nonsecure subresources that this class keeps track of.
- //
- // TODO(estark): Currently, MIXED_CONTENT is used for all insecure
- // content, as SSLManager/SSLPolicy do not separate signals for mixed
- // content from signals for subresources with cert errors. Fixing this
- // is in progress as part of https://crbug.com/634171.
enum InsecureContentType {
// A MIXED subresource was loaded over HTTP on an HTTPS page.
MIXED_CONTENT,