diff options
author | abarth@chromium.org <abarth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-20 04:30:23 +0000 |
---|---|---|
committer | abarth@chromium.org <abarth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-05-20 04:30:23 +0000 |
commit | a9cea754e016601a59cb07be2946559a9ad21738 (patch) | |
tree | d4c5baf30736f27de914f5091fde20707d1c9e87 | |
parent | a65d1b09eb7adb31e9ac975962c19cdc15c44d97 (diff) | |
download | chromium_src-a9cea754e016601a59cb07be2946559a9ad21738.zip chromium_src-a9cea754e016601a59cb07be2946559a9ad21738.tar.gz chromium_src-a9cea754e016601a59cb07be2946559a9ad21738.tar.bz2 |
More progress on ForceHTTPS.
Instead of turning on strict HTTPS error processing for every site, we now track which sites have opted in. Our implementation is still experimental and hidden behing the command line switch --force-https.
R=darin
TEST=No tests yet because this is just an experiment.
Review URL: http://codereview.chromium.org/113503
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@16464 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/net/chrome_url_request_context.cc | 2 | ||||
-rw-r--r-- | chrome/browser/profile.cc | 18 | ||||
-rw-r--r-- | chrome/browser/profile.h | 10 | ||||
-rw-r--r-- | chrome/browser/ssl/ssl_policy.cc | 14 | ||||
-rw-r--r-- | chrome/browser/ssl/ssl_policy_backend.cc | 8 | ||||
-rw-r--r-- | chrome/browser/ssl/ssl_policy_backend.h | 10 | ||||
-rw-r--r-- | chrome/test/testing_profile.h | 3 | ||||
-rw-r--r-- | net/base/force_tls_state.cc | 34 | ||||
-rw-r--r-- | net/base/force_tls_state.h | 50 | ||||
-rw-r--r-- | net/net.gyp | 2 | ||||
-rw-r--r-- | net/url_request/url_request_context.h | 7 | ||||
-rw-r--r-- | net/url_request/url_request_http_job.cc | 57 | ||||
-rw-r--r-- | net/url_request/url_request_http_job.h | 5 |
13 files changed, 210 insertions, 10 deletions
diff --git a/chrome/browser/net/chrome_url_request_context.cc b/chrome/browser/net/chrome_url_request_context.cc index 06b3739..3ea9cc1 100644 --- a/chrome/browser/net/chrome_url_request_context.cc +++ b/chrome/browser/net/chrome_url_request_context.cc @@ -292,6 +292,8 @@ ChromeURLRequestContext::ChromeURLRequestContext(Profile* profile) cookie_policy_.SetType(net::CookiePolicy::FromInt( prefs_->GetInteger(prefs::kCookieBehavior))); + force_tls_state_ = profile->GetForceTLSState(); + if (profile->GetExtensionsService()) { const ExtensionList* extensions = profile->GetExtensionsService()->extensions(); diff --git a/chrome/browser/profile.cc b/chrome/browser/profile.cc index 1c76c49..cdb7c00 100644 --- a/chrome/browser/profile.cc +++ b/chrome/browser/profile.cc @@ -39,6 +39,7 @@ #include "chrome/common/pref_names.h" #include "chrome/common/render_messages.h" #include "grit/locale_settings.h" +#include "net/base/force_tls_state.h" using base::Time; using base::TimeDelta; @@ -171,6 +172,13 @@ class OffTheRecordProfileImpl : public Profile, return ssl_host_state_.get(); } + virtual net::ForceTLSState* GetForceTLSState() { + if (!force_tls_state_.get()) + force_tls_state_.reset(new net::ForceTLSState()); + + return force_tls_state_.get(); + } + virtual HistoryService* GetHistoryService(ServiceAccessType sat) { if (sat == EXPLICIT_ACCESS) { return profile_->GetHistoryService(sat); @@ -389,6 +397,9 @@ class OffTheRecordProfileImpl : public Profile, // the user visited while OTR. scoped_ptr<SSLHostState> ssl_host_state_; + // The ForceTLSState that only stores enabled sites in memory. + scoped_ptr<net::ForceTLSState> force_tls_state_; + // Extensions run in a different context in incognito mode. scoped_ptr<ExtensionProcessManager> extension_process_manager_; @@ -627,6 +638,13 @@ SSLHostState* ProfileImpl::GetSSLHostState() { return ssl_host_state_.get(); } +net::ForceTLSState* ProfileImpl::GetForceTLSState() { + if (!force_tls_state_.get()) + force_tls_state_.reset(new net::ForceTLSState()); + + return force_tls_state_.get(); +} + PrefService* ProfileImpl::GetPrefs() { if (!prefs_.get()) { prefs_.reset(new PrefService(GetPrefFilePath(), diff --git a/chrome/browser/profile.h b/chrome/browser/profile.h index 6ec129c..be775c2 100644 --- a/chrome/browser/profile.h +++ b/chrome/browser/profile.h @@ -20,6 +20,9 @@ #endif #include "chrome/common/notification_observer.h" +namespace net { +class ForceTLSState; +} class BookmarkModel; class ChromeURLRequestContext; class DownloadManager; @@ -128,6 +131,11 @@ class Profile { // called. virtual SSLHostState* GetSSLHostState() = 0; + // Retrieves a pointer to the ForceTLStSate associated with this profile. + // The ForceTLSState is lazily created the first time that this method is + // called. + virtual net::ForceTLSState* GetForceTLSState() = 0; + // Retrieves a pointer to the HistoryService associated with this // profile. The HistoryService is lazily created the first time // that this method is called. @@ -301,6 +309,7 @@ class ProfileImpl : public Profile, virtual VisitedLinkMaster* GetVisitedLinkMaster(); virtual UserScriptMaster* GetUserScriptMaster(); virtual SSLHostState* GetSSLHostState(); + virtual net::ForceTLSState* GetForceTLSState(); virtual ExtensionsService* GetExtensionsService(); virtual ExtensionProcessManager* GetExtensionProcessManager(); virtual HistoryService* GetHistoryService(ServiceAccessType sat); @@ -371,6 +380,7 @@ class ProfileImpl : public Profile, scoped_refptr<UserScriptMaster> user_script_master_; scoped_ptr<ExtensionProcessManager> extension_process_manager_; scoped_ptr<SSLHostState> ssl_host_state_; + scoped_ptr<net::ForceTLSState> force_tls_state_; scoped_ptr<PrefService> prefs_; scoped_ptr<TemplateURLFetcher> template_url_fetcher_; scoped_ptr<TemplateURLModel> template_url_model_; diff --git a/chrome/browser/ssl/ssl_policy.cc b/chrome/browser/ssl/ssl_policy.cc index 7004da7..3bf64e5 100644 --- a/chrome/browser/ssl/ssl_policy.cc +++ b/chrome/browser/ssl/ssl_policy.cc @@ -6,6 +6,8 @@ #include "app/l10n_util.h" #include "app/resource_bundle.h" +#include "base/base_switches.h" +#include "base/command_line.h" #include "base/singleton.h" #include "base/string_piece.h" #include "base/string_util.h" @@ -117,11 +119,15 @@ void SSLPolicy::OnMixedContent(SSLMixedContentHandler* handler) { // If the user has added an exception, doctor the |filter_policy|. std::string host = GURL(handler->main_frame_origin()).host(); - if (backend_->DidAllowMixedContentForHost(host) || - backend_->DidMarkHostAsBroken(host, handler->pid())) + if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kForceHTTPS) && + backend_->IsForceTLSEnabledForHost(host)) { + // We're supposed to block all mixed content for this host. + filter_policy = FilterPolicy::FILTER_ALL; + } else if (backend_->DidAllowMixedContentForHost(host) || + backend_->DidMarkHostAsBroken(host, handler->pid())) { + // Let the mixed content through. filter_policy = FilterPolicy::DONT_FILTER; - - if (filter_policy != FilterPolicy::DONT_FILTER) { + } else if (filter_policy != FilterPolicy::DONT_FILTER) { backend_->ShowMessageWithLink( l10n_util::GetString(IDS_SSL_INFO_BAR_FILTERED_CONTENT), l10n_util::GetString(IDS_SSL_INFO_BAR_SHOW_CONTENT), diff --git a/chrome/browser/ssl/ssl_policy_backend.cc b/chrome/browser/ssl/ssl_policy_backend.cc index 9b1eed8..8852190 100644 --- a/chrome/browser/ssl/ssl_policy_backend.cc +++ b/chrome/browser/ssl/ssl_policy_backend.cc @@ -13,6 +13,7 @@ #include "chrome/common/notification_service.h" #include "grit/generated_resources.h" #include "grit/theme_resources.h" +#include "net/base/force_tls_state.h" using WebKit::WebConsoleMessage; @@ -67,7 +68,8 @@ class SSLInfoBarDelegate : public ConfirmInfoBarDelegate { SSLPolicyBackend::SSLPolicyBackend(NavigationController* controller) : controller_(controller), - ssl_host_state_(controller->profile()->GetSSLHostState()) { + ssl_host_state_(controller->profile()->GetSSLHostState()), + force_tls_state_(controller->profile()->GetForceTLSState()) { DCHECK(controller_); } @@ -159,6 +161,10 @@ bool SSLPolicyBackend::DidAllowMixedContentForHost( return ssl_host_state_->DidAllowMixedContentForHost(host); } +bool SSLPolicyBackend::IsForceTLSEnabledForHost(const std::string& host) const { + return force_tls_state_->IsEnabledForHost(host); +} + void SSLPolicyBackend::Reload() { controller_->Reload(true); } diff --git a/chrome/browser/ssl/ssl_policy_backend.h b/chrome/browser/ssl/ssl_policy_backend.h index f8a829c..2d84232 100644 --- a/chrome/browser/ssl/ssl_policy_backend.h +++ b/chrome/browser/ssl/ssl_policy_backend.h @@ -13,6 +13,9 @@ #include "net/base/x509_certificate.h" #include "webkit/api/public/WebConsoleMessage.h" +namespace net { +class ForceTLSState; +} class NavigationController; class SSLHostState; class Task; @@ -68,6 +71,9 @@ class SSLPolicyBackend { // Returns whether the specified host is allowed to show mixed content. bool DidAllowMixedContentForHost(const std::string& host) const; + // Returns whether ForceTLS is enabled for |host|. + bool IsForceTLSEnabledForHost(const std::string& host) const; + // Reloads the tab. void Reload(); @@ -112,6 +118,10 @@ class SSLPolicyBackend { // SSL state specific for each host. SSLHostState* ssl_host_state_; + // ForceTLS state. + // TODO(abarth): Consider combining with SSLHostState? + net::ForceTLSState* force_tls_state_; + // The list of messages that should be displayed (in info bars) when the page // currently loading had loaded. std::vector<SSLMessageInfo> pending_messages_; diff --git a/chrome/test/testing_profile.h b/chrome/test/testing_profile.h index f83e5e4..974d31d 100644 --- a/chrome/test/testing_profile.h +++ b/chrome/test/testing_profile.h @@ -90,6 +90,9 @@ class TestingProfile : public Profile { virtual SSLHostState* GetSSLHostState() { return NULL; } + virtual net::ForceTLSState* GetForceTLSState() { + return NULL; + } virtual HistoryService* GetHistoryService(ServiceAccessType access) { return history_service_.get(); } diff --git a/net/base/force_tls_state.cc b/net/base/force_tls_state.cc new file mode 100644 index 0000000..4be33f5 --- /dev/null +++ b/net/base/force_tls_state.cc @@ -0,0 +1,34 @@ +// Copyright (c) 2009 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 "net/base/force_tls_state.h" + +#include "base/logging.h" +#include "googleurl/src/gurl.h" +#include "net/base/registry_controlled_domain.h" + +namespace net { + +ForceTLSState::ForceTLSState() { +} + +void ForceTLSState::DidReceiveHeader(const GURL& url, + const std::string& value) { + // TODO(abarth): Actually parse |value| once the spec settles down. + EnableHost(url.host()); +} + +void ForceTLSState::EnableHost(const std::string& host) { + // TODO(abarth): Canonicalize host. + AutoLock lock(lock_); + enabled_hosts_.insert(host); +} + +bool ForceTLSState::IsEnabledForHost(const std::string& host) { + // TODO(abarth): Canonicalize host. + AutoLock lock(lock_); + return enabled_hosts_.find(host) != enabled_hosts_.end(); +} + +} // namespace diff --git a/net/base/force_tls_state.h b/net/base/force_tls_state.h new file mode 100644 index 0000000..988e9c07 --- /dev/null +++ b/net/base/force_tls_state.h @@ -0,0 +1,50 @@ +// Copyright (c) 2009 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 NET_BASE_FORCE_TLS_STATE_H_ +#define NET_BASE_FORCE_TLS_STATE_H_ + +#include <set> +#include <string> + +#include "base/basictypes.h" +#include "base/lock.h" + +class GURL; + +namespace net { + +// ForceTLSState +// +// Tracks which hosts have enabled ForceTLS. After a host enables ForceTLS, +// then we refuse to talk to the host over HTTP, treat all certificate errors as +// fatal, and refuses to load any mixed content. +// +class ForceTLSState { + public: + ForceTLSState(); + + // Called when we see an X-Force-TLS header that we should process. Modifies + // our state as instructed by the header. + void DidReceiveHeader(const GURL& url, const std::string& value); + + // Enable ForceTLS for |host|. + void EnableHost(const std::string& host); + + // Returns whether |host| has had ForceTLS enabled. + bool IsEnabledForHost(const std::string& host); + + private: + // The set of hosts that have enabled ForceTLS. + std::set<std::string> enabled_hosts_; + + // Protect access to our data members with this lock. + Lock lock_; + + DISALLOW_COPY_AND_ASSIGN(ForceTLSState); +}; + +} // namespace net + +#endif // NET_BASE_FORCE_TLS_STATE_H_ diff --git a/net/net.gyp b/net/net.gyp index 8c11266..778f2da 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -75,6 +75,8 @@ 'base/file_stream_win.cc', 'base/filter.cc', 'base/filter.h', + 'base/force_tls_state.cc', + 'base/force_tls_state.h', 'base/gzip_filter.cc', 'base/gzip_filter.h', 'base/gzip_header.cc', diff --git a/net/url_request/url_request_context.h b/net/url_request/url_request_context.h index 29735ac..8e32c97 100644 --- a/net/url_request/url_request_context.h +++ b/net/url_request/url_request_context.h @@ -17,6 +17,7 @@ namespace net { class CookieMonster; +class ForceTLSState; class FtpTransactionFactory; class HttpTransactionFactory; class ProxyService; @@ -30,7 +31,8 @@ class URLRequestContext : : proxy_service_(NULL), http_transaction_factory_(NULL), ftp_transaction_factory_(NULL), - cookie_store_(NULL) { + cookie_store_(NULL), + force_tls_state_(NULL) { } // Get the proxy service for this context. @@ -54,6 +56,8 @@ class URLRequestContext : // Gets the cookie policy for this context. net::CookiePolicy* cookie_policy() { return &cookie_policy_; } + net::ForceTLSState* force_tls_state() { return force_tls_state_; } + // Gets the FTP authentication cache for this context. net::FtpAuthCache* ftp_auth_cache() { return &ftp_auth_cache_; } @@ -89,6 +93,7 @@ class URLRequestContext : net::FtpTransactionFactory* ftp_transaction_factory_; net::CookieMonster* cookie_store_; net::CookiePolicy cookie_policy_; + net::ForceTLSState* force_tls_state_;; net::FtpAuthCache ftp_auth_cache_; std::string accept_language_; std::string accept_charset_; diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc index a86edbd..eff2344 100644 --- a/net/url_request/url_request_http_job.cc +++ b/net/url_request/url_request_http_job.cc @@ -12,8 +12,10 @@ #include "base/message_loop.h" #include "base/rand_util.h" #include "base/string_util.h" +#include "net/base/cert_status_flags.h" #include "net/base/cookie_monster.h" #include "net/base/filter.h" +#include "net/base/force_tls_state.h" #include "net/base/load_flags.h" #include "net/base/net_errors.h" #include "net/base/net_util.h" @@ -47,7 +49,10 @@ URLRequestJob* URLRequestHttpJob::Factory(URLRequest* request, // network request. static const bool kForceHTTPS = CommandLine::ForCurrentProcess()->HasSwitch(switches::kForceHTTPS); - if (kForceHTTPS && scheme != "https") + if (kForceHTTPS && scheme == "http" && + request->context()->force_tls_state() && + request->context()->force_tls_state()->IsEnabledForHost( + request->url().host())) return new URLRequestErrorJob(request, net::ERR_DISALLOWED_URL_SCHEME); return new URLRequestHttpJob(request); @@ -441,9 +446,7 @@ void URLRequestHttpJob::OnStartCompleted(int result) { if (result == net::OK) { NotifyHeadersComplete(); - } else if (net::IsCertificateError(result) && - !CommandLine::ForCurrentProcess()->HasSwitch( - switches::kForceHTTPS)) { + } else if (ShouldTreatAsCertificateError(result)) { // We encountered an SSL certificate error. Ask our delegate to decide // what we should do. // TODO(wtc): also pass ssl_info.cert_status, or just pass the whole @@ -470,6 +473,22 @@ void URLRequestHttpJob::OnReadCompleted(int result) { NotifyReadComplete(result); } +bool URLRequestHttpJob::ShouldTreatAsCertificateError(int result) { + if (!net::IsCertificateError(result)) + return false; + + // Hide the fancy processing behind a command line switch. + if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kForceHTTPS)) + return true; + + // Check whether our context is using ForceTLS. + if (!context_->force_tls_state()) + return true; + + return !context_->force_tls_state()->IsEnabledForHost( + request_info_.url.host()); +} + void URLRequestHttpJob::NotifyHeadersComplete() { DCHECK(!response_info_); @@ -494,6 +513,8 @@ void URLRequestHttpJob::NotifyHeadersComplete() { } } + ProcessForceTLSHeader(); + if (SdchManager::Global() && SdchManager::Global()->IsInSupportedDomain(request_->url())) { static const std::string name = "Get-Dictionary"; @@ -657,3 +678,31 @@ void URLRequestHttpJob::FetchResponseCookies() { while (response_info_->headers->EnumerateHeader(&iter, name, &value)) response_cookies_.push_back(value); } + + +void URLRequestHttpJob::ProcessForceTLSHeader() { + DCHECK(response_info_); + + // Hide processing behind a command line flag. + if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kForceHTTPS)) + return; + + // Only process X-Force-TLS from HTTPS responses. + if (request_info_.url.scheme() != "https") + return; + + // Only process X-Force-TLS from responses with valid certificates. + if (response_info_->ssl_info.cert_status & net::CERT_STATUS_ALL_ERRORS) + return; + + URLRequestContext* ctx = request_->context(); + if (!ctx || !ctx->force_tls_state()) + return; + + std::string name = "X-Force-TLS"; + std::string value; + + void* iter = NULL; + while (response_info_->headers->EnumerateHeader(&iter, name, &value)) + ctx->force_tls_state()->DidReceiveHeader(request_info_.url, value); +} diff --git a/net/url_request/url_request_http_job.h b/net/url_request/url_request_http_job.h index a946f62..7853f83 100644 --- a/net/url_request/url_request_http_job.h +++ b/net/url_request/url_request_http_job.h @@ -67,9 +67,14 @@ class URLRequestHttpJob : public URLRequestJob { std::string AssembleRequestCookies(); void FetchResponseCookies(); + // Process the X-Force-TLS header, if one exists. + void ProcessForceTLSHeader(); + void OnStartCompleted(int result); void OnReadCompleted(int result); + bool ShouldTreatAsCertificateError(int result); + void RestartTransactionWithAuth(const std::wstring& username, const std::wstring& password); |