Index: chrome/browser/ssl/chrome_security_state_model_client_browser_tests.cc |
diff --git a/chrome/browser/ssl/chrome_security_state_model_client_browser_tests.cc b/chrome/browser/ssl/chrome_security_state_model_client_browser_tests.cc |
index d2c41d7c1bcc7e29bcbc91f3c32600f58cfbdc2b..c32738337731383b6506a0c5cbd0bfaf945c8ffc 100644 |
--- a/chrome/browser/ssl/chrome_security_state_model_client_browser_tests.cc |
+++ b/chrome/browser/ssl/chrome_security_state_model_client_browser_tests.cc |
@@ -8,43 +8,158 @@ |
#include "base/files/file_path.h" |
#include "base/macros.h" |
#include "base/strings/string_split.h" |
+#include "base/strings/utf_string_conversions.h" |
#include "chrome/browser/ssl/cert_verifier_browser_test.h" |
#include "chrome/browser/ssl/chrome_security_state_model_client.h" |
#include "chrome/browser/ssl/ssl_blocking_page.h" |
#include "chrome/browser/ui/browser.h" |
+#include "chrome/browser/ui/browser_commands.h" |
#include "chrome/browser/ui/tabs/tab_strip_model.h" |
#include "chrome/common/chrome_paths.h" |
#include "chrome/common/chrome_switches.h" |
#include "chrome/common/pref_names.h" |
+#include "chrome/grit/generated_resources.h" |
#include "chrome/test/base/in_process_browser_test.h" |
#include "chrome/test/base/ui_test_utils.h" |
#include "components/prefs/pref_service.h" |
#include "content/public/browser/cert_store.h" |
#include "content/public/browser/interstitial_page.h" |
#include "content/public/browser/navigation_controller.h" |
+#include "content/public/browser/navigation_entry.h" |
#include "content/public/browser/notification_service.h" |
#include "content/public/browser/notification_types.h" |
+#include "content/public/browser/security_style_explanation.h" |
+#include "content/public/browser/security_style_explanations.h" |
#include "content/public/browser/web_contents.h" |
#include "content/public/common/referrer.h" |
+#include "content/public/common/ssl_status.h" |
#include "content/public/test/browser_test_utils.h" |
#include "net/base/net_errors.h" |
+#include "net/base/test_data_directory.h" |
#include "net/cert/cert_status_flags.h" |
#include "net/cert/cert_verify_result.h" |
#include "net/cert/mock_cert_verifier.h" |
#include "net/cert/x509_certificate.h" |
#include "net/dns/mock_host_resolver.h" |
+#include "net/ssl/ssl_cipher_suite_names.h" |
+#include "net/ssl/ssl_connection_status_flags.h" |
+#include "net/test/cert_test_util.h" |
#include "net/test/embedded_test_server/embedded_test_server.h" |
#include "net/test/embedded_test_server/request_handler_util.h" |
#include "net/test/url_request/url_request_failed_job.h" |
+#include "net/test/url_request/url_request_mock_http_job.h" |
#include "net/url_request/url_request_filter.h" |
+#include "net/url_request/url_request_test_util.h" |
+#include "ui/base/l10n/l10n_util.h" |
using security_state::SecurityStateModel; |
namespace { |
+enum CertificateStatus { VALID_CERTIFICATE, INVALID_CERTIFICATE }; |
+ |
const base::FilePath::CharType kDocRoot[] = |
FILE_PATH_LITERAL("chrome/test/data"); |
+// A WebContentsObserver useful for testing the SecurityStyleChanged() |
+// method: it keeps track of the latest security style and explanation |
+// that was fired. |
+class SecurityStyleTestObserver : public content::WebContentsObserver { |
+ public: |
+ explicit SecurityStyleTestObserver(content::WebContents* web_contents) |
+ : content::WebContentsObserver(web_contents), |
+ latest_security_style_(content::SECURITY_STYLE_UNKNOWN) {} |
+ ~SecurityStyleTestObserver() override {} |
+ |
+ void SecurityStyleChanged(content::SecurityStyle security_style, |
+ const content::SecurityStyleExplanations& |
+ security_style_explanations) override { |
+ latest_security_style_ = security_style; |
+ latest_explanations_ = security_style_explanations; |
+ } |
+ |
+ content::SecurityStyle latest_security_style() const { |
+ return latest_security_style_; |
+ } |
+ |
+ const content::SecurityStyleExplanations& latest_explanations() const { |
+ return latest_explanations_; |
+ } |
+ |
+ void ClearLatestSecurityStyleAndExplanations() { |
+ latest_security_style_ = content::SECURITY_STYLE_UNKNOWN; |
+ latest_explanations_ = content::SecurityStyleExplanations(); |
+ } |
+ |
+ private: |
+ content::SecurityStyle latest_security_style_; |
+ content::SecurityStyleExplanations latest_explanations_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(SecurityStyleTestObserver); |
+}; |
+ |
+// Check that |observer|'s latest event was for an expired certificate |
+// and that it saw the proper SecurityStyle and explanations. |
+void CheckBrokenSecurityStyle(const SecurityStyleTestObserver& observer, |
+ int error, |
+ Browser* browser) { |
+ EXPECT_EQ(content::SECURITY_STYLE_AUTHENTICATION_BROKEN, |
+ observer.latest_security_style()); |
+ |
+ const content::SecurityStyleExplanations& expired_explanation = |
+ observer.latest_explanations(); |
+ EXPECT_EQ(0u, expired_explanation.unauthenticated_explanations.size()); |
+ ASSERT_EQ(1u, expired_explanation.broken_explanations.size()); |
+ |
+ // Check that the summary and description are as expected. |
+ EXPECT_EQ(l10n_util::GetStringUTF8(IDS_CERTIFICATE_CHAIN_ERROR), |
+ expired_explanation.broken_explanations[0].summary); |
+ |
+ base::string16 error_string = base::UTF8ToUTF16(net::ErrorToString(error)); |
+ EXPECT_EQ(l10n_util::GetStringFUTF8( |
+ IDS_CERTIFICATE_CHAIN_ERROR_DESCRIPTION_FORMAT, error_string), |
+ expired_explanation.broken_explanations[0].description); |
+ |
+ // Check the associated certificate id. |
+ int cert_id = browser->tab_strip_model() |
+ ->GetActiveWebContents() |
+ ->GetController() |
+ .GetActiveEntry() |
+ ->GetSSL() |
+ .cert_id; |
+ EXPECT_EQ(cert_id, expired_explanation.broken_explanations[0].cert_id); |
+} |
+ |
+// Checks that the given |secure_explanations| contains an appropriate |
+// explanation if the certificate status is valid. |
+void CheckSecureExplanations( |
+ const std::vector<content::SecurityStyleExplanation>& secure_explanations, |
+ CertificateStatus cert_status, |
+ Browser* browser) { |
+ ASSERT_EQ(cert_status == VALID_CERTIFICATE ? 2u : 1u, |
+ secure_explanations.size()); |
+ if (cert_status == VALID_CERTIFICATE) { |
+ EXPECT_EQ(l10n_util::GetStringUTF8(IDS_VALID_SERVER_CERTIFICATE), |
+ secure_explanations[0].summary); |
+ EXPECT_EQ( |
+ l10n_util::GetStringUTF8(IDS_VALID_SERVER_CERTIFICATE_DESCRIPTION), |
+ secure_explanations[0].description); |
+ int cert_id = browser->tab_strip_model() |
+ ->GetActiveWebContents() |
+ ->GetController() |
+ .GetActiveEntry() |
+ ->GetSSL() |
+ .cert_id; |
+ EXPECT_EQ(cert_id, secure_explanations[0].cert_id); |
+ } |
+ |
+ EXPECT_EQ(l10n_util::GetStringUTF8(IDS_SECURE_PROTOCOL_AND_CIPHERSUITE), |
+ secure_explanations.back().summary); |
+ EXPECT_EQ( |
+ l10n_util::GetStringUTF8(IDS_SECURE_PROTOCOL_AND_CIPHERSUITE_DESCRIPTION), |
+ secure_explanations.back().description); |
+} |
+ |
void CheckSecurityInfoForSecure( |
content::WebContents* contents, |
SecurityStateModel::SecurityLevel expect_security_level, |
@@ -92,6 +207,29 @@ void CheckSecurityInfoForNonSecure(content::WebContents* contents) { |
EXPECT_EQ(0, security_info.cert_id); |
} |
+void ProceedThroughInterstitial(content::WebContents* tab) { |
+ content::InterstitialPage* interstitial_page = tab->GetInterstitialPage(); |
+ ASSERT_TRUE(interstitial_page); |
+ ASSERT_EQ(SSLBlockingPage::kTypeForTesting, |
+ interstitial_page->GetDelegateForTesting()->GetTypeForTesting()); |
+ content::WindowedNotificationObserver observer( |
+ content::NOTIFICATION_LOAD_STOP, |
+ content::Source<content::NavigationController>(&tab->GetController())); |
+ interstitial_page->Proceed(); |
+ observer.Wait(); |
+} |
+ |
+void GetFilePathWithHostAndPortReplacement( |
+ const std::string& original_file_path, |
+ const net::HostPortPair& host_port_pair, |
+ std::string* replacement_path) { |
+ base::StringPairs replacement_text; |
+ replacement_text.push_back( |
+ make_pair("REPLACE_WITH_HOST_AND_PORT", host_port_pair.ToString())); |
+ net::test_server::GetFilePathWithReplacements( |
+ original_file_path, replacement_text, replacement_path); |
+} |
+ |
class ChromeSecurityStateModelClientTest : public CertVerifierBrowserTest { |
public: |
ChromeSecurityStateModelClientTest() |
@@ -104,29 +242,6 @@ class ChromeSecurityStateModelClientTest : public CertVerifierBrowserTest { |
command_line->AppendSwitch(switches::kAllowRunningInsecureContent); |
} |
- void ProceedThroughInterstitial(content::WebContents* tab) { |
- content::InterstitialPage* interstitial_page = tab->GetInterstitialPage(); |
- ASSERT_TRUE(interstitial_page); |
- ASSERT_EQ(SSLBlockingPage::kTypeForTesting, |
- interstitial_page->GetDelegateForTesting()->GetTypeForTesting()); |
- content::WindowedNotificationObserver observer( |
- content::NOTIFICATION_LOAD_STOP, |
- content::Source<content::NavigationController>(&tab->GetController())); |
- interstitial_page->Proceed(); |
- observer.Wait(); |
- } |
- |
- static void GetFilePathWithHostAndPortReplacement( |
- const std::string& original_file_path, |
- const net::HostPortPair& host_port_pair, |
- std::string* replacement_path) { |
- base::StringPairs replacement_text; |
- replacement_text.push_back( |
- make_pair("REPLACE_WITH_HOST_AND_PORT", host_port_pair.ToString())); |
- net::test_server::GetFilePathWithReplacements( |
- original_file_path, replacement_text, replacement_path); |
- } |
- |
protected: |
void SetUpMockCertVerifierForHttpsServer(net::CertStatus cert_status, |
int net_result) { |
@@ -146,6 +261,25 @@ class ChromeSecurityStateModelClientTest : public CertVerifierBrowserTest { |
DISALLOW_COPY_AND_ASSIGN(ChromeSecurityStateModelClientTest); |
}; |
+class SecurityStyleChangedTest : public InProcessBrowserTest { |
+ public: |
+ SecurityStyleChangedTest() |
+ : https_server_(net::EmbeddedTestServer::TYPE_HTTPS) { |
+ https_server_.ServeFilesFromSourceDirectory(base::FilePath(kDocRoot)); |
+ } |
+ |
+ void SetUpCommandLine(base::CommandLine* command_line) override { |
+ // Browser will both run and display insecure content. |
+ command_line->AppendSwitch(switches::kAllowRunningInsecureContent); |
+ } |
+ |
+ protected: |
+ net::EmbeddedTestServer https_server_; |
+ |
+ private: |
+ DISALLOW_COPY_AND_ASSIGN(SecurityStyleChangedTest); |
+}; |
+ |
IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTest, HttpPage) { |
ASSERT_TRUE(embedded_test_server()->Start()); |
ui_test_utils::NavigateToURL( |
@@ -535,4 +669,329 @@ IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTest, AddedTab) { |
false /* expect cert status error */); |
} |
+// Tests that the WebContentsObserver::SecurityStyleChanged event fires |
+// with the current style on HTTP, broken HTTPS, and valid HTTPS pages. |
+IN_PROC_BROWSER_TEST_F(SecurityStyleChangedTest, SecurityStyleChangedObserver) { |
+ ASSERT_TRUE(https_server_.Start()); |
+ ASSERT_TRUE(embedded_test_server()->Start()); |
+ |
+ net::EmbeddedTestServer https_test_server_expired( |
+ net::EmbeddedTestServer::TYPE_HTTPS); |
+ https_test_server_expired.SetSSLConfig(net::EmbeddedTestServer::CERT_EXPIRED); |
+ https_test_server_expired.ServeFilesFromSourceDirectory( |
+ base::FilePath(kDocRoot)); |
+ ASSERT_TRUE(https_test_server_expired.Start()); |
+ |
+ content::WebContents* web_contents = |
+ browser()->tab_strip_model()->GetActiveWebContents(); |
+ SecurityStyleTestObserver observer(web_contents); |
+ |
+ // Visit an HTTP url. |
+ GURL http_url(embedded_test_server()->GetURL("/")); |
+ ui_test_utils::NavigateToURL(browser(), http_url); |
+ EXPECT_EQ(content::SECURITY_STYLE_UNAUTHENTICATED, |
+ observer.latest_security_style()); |
+ EXPECT_EQ(0u, |
+ observer.latest_explanations().unauthenticated_explanations.size()); |
+ EXPECT_EQ(0u, observer.latest_explanations().broken_explanations.size()); |
+ EXPECT_EQ(0u, observer.latest_explanations().secure_explanations.size()); |
+ EXPECT_FALSE(observer.latest_explanations().scheme_is_cryptographic); |
+ EXPECT_FALSE(observer.latest_explanations().ran_insecure_content); |
+ EXPECT_FALSE(observer.latest_explanations().displayed_insecure_content); |
+ |
+ // Visit an (otherwise valid) HTTPS page that displays mixed content. |
+ std::string replacement_path; |
+ GetFilePathWithHostAndPortReplacement( |
+ "/ssl/page_displays_insecure_content.html", |
+ embedded_test_server()->host_port_pair(), &replacement_path); |
+ |
+ GURL mixed_content_url(https_server_.GetURL(replacement_path)); |
+ ui_test_utils::NavigateToURL(browser(), mixed_content_url); |
+ EXPECT_EQ(content::SECURITY_STYLE_UNAUTHENTICATED, |
+ observer.latest_security_style()); |
+ |
+ const content::SecurityStyleExplanations& mixed_content_explanation = |
+ observer.latest_explanations(); |
+ ASSERT_EQ(0u, mixed_content_explanation.unauthenticated_explanations.size()); |
+ ASSERT_EQ(0u, mixed_content_explanation.broken_explanations.size()); |
+ CheckSecureExplanations(mixed_content_explanation.secure_explanations, |
+ VALID_CERTIFICATE, browser()); |
+ EXPECT_TRUE(mixed_content_explanation.scheme_is_cryptographic); |
+ EXPECT_TRUE(mixed_content_explanation.displayed_insecure_content); |
+ EXPECT_FALSE(mixed_content_explanation.ran_insecure_content); |
+ EXPECT_EQ(content::SECURITY_STYLE_UNAUTHENTICATED, |
+ mixed_content_explanation.displayed_insecure_content_style); |
+ EXPECT_EQ(content::SECURITY_STYLE_AUTHENTICATION_BROKEN, |
+ mixed_content_explanation.ran_insecure_content_style); |
+ |
+ // Visit a broken HTTPS url. |
+ GURL expired_url(https_test_server_expired.GetURL(std::string("/"))); |
+ ui_test_utils::NavigateToURL(browser(), expired_url); |
+ |
+ // An interstitial should show, and an event for the lock icon on the |
+ // interstitial should fire. |
+ content::WaitForInterstitialAttach(web_contents); |
+ EXPECT_TRUE(web_contents->ShowingInterstitialPage()); |
+ CheckBrokenSecurityStyle(observer, net::ERR_CERT_DATE_INVALID, browser()); |
+ CheckSecureExplanations(observer.latest_explanations().secure_explanations, |
+ INVALID_CERTIFICATE, browser()); |
+ EXPECT_TRUE(observer.latest_explanations().scheme_is_cryptographic); |
+ EXPECT_FALSE(observer.latest_explanations().displayed_insecure_content); |
+ EXPECT_FALSE(observer.latest_explanations().ran_insecure_content); |
+ |
+ // Before clicking through, navigate to a different page, and then go |
+ // back to the interstitial. |
+ GURL valid_https_url(https_server_.GetURL(std::string("/"))); |
+ ui_test_utils::NavigateToURL(browser(), valid_https_url); |
+ EXPECT_EQ(content::SECURITY_STYLE_AUTHENTICATED, |
+ observer.latest_security_style()); |
+ EXPECT_EQ(0u, |
+ observer.latest_explanations().unauthenticated_explanations.size()); |
+ EXPECT_EQ(0u, observer.latest_explanations().broken_explanations.size()); |
+ CheckSecureExplanations(observer.latest_explanations().secure_explanations, |
+ VALID_CERTIFICATE, browser()); |
+ EXPECT_TRUE(observer.latest_explanations().scheme_is_cryptographic); |
+ EXPECT_FALSE(observer.latest_explanations().displayed_insecure_content); |
+ EXPECT_FALSE(observer.latest_explanations().ran_insecure_content); |
+ |
+ // After going back to the interstitial, an event for a broken lock |
+ // icon should fire again. |
+ ui_test_utils::NavigateToURL(browser(), expired_url); |
+ content::WaitForInterstitialAttach(web_contents); |
+ EXPECT_TRUE(web_contents->ShowingInterstitialPage()); |
+ CheckBrokenSecurityStyle(observer, net::ERR_CERT_DATE_INVALID, browser()); |
+ CheckSecureExplanations(observer.latest_explanations().secure_explanations, |
+ INVALID_CERTIFICATE, browser()); |
+ EXPECT_TRUE(observer.latest_explanations().scheme_is_cryptographic); |
+ EXPECT_FALSE(observer.latest_explanations().displayed_insecure_content); |
+ EXPECT_FALSE(observer.latest_explanations().ran_insecure_content); |
+ |
+ // Since the next expected style is the same as the previous, clear |
+ // the observer (to make sure that the event fires twice and we don't |
+ // just see the previous event's style). |
+ observer.ClearLatestSecurityStyleAndExplanations(); |
+ |
+ // Other conditions cannot be tested on this host after clicking |
+ // through because once the interstitial is clicked through, all URLs |
+ // for this host will remain in a broken state. |
+ ProceedThroughInterstitial(web_contents); |
+ CheckBrokenSecurityStyle(observer, net::ERR_CERT_DATE_INVALID, browser()); |
+ CheckSecureExplanations(observer.latest_explanations().secure_explanations, |
+ INVALID_CERTIFICATE, browser()); |
+ EXPECT_TRUE(observer.latest_explanations().scheme_is_cryptographic); |
+ EXPECT_FALSE(observer.latest_explanations().displayed_insecure_content); |
+ EXPECT_FALSE(observer.latest_explanations().ran_insecure_content); |
+} |
+ |
+// Visit a valid HTTPS page, then a broken HTTPS page, and then go back, |
+// and test that the observed security style matches. |
+IN_PROC_BROWSER_TEST_F(SecurityStyleChangedTest, |
+ SecurityStyleChangedObserverGoBack) { |
+ ASSERT_TRUE(https_server_.Start()); |
+ |
+ net::EmbeddedTestServer https_test_server_expired( |
+ net::EmbeddedTestServer::TYPE_HTTPS); |
+ https_test_server_expired.SetSSLConfig(net::EmbeddedTestServer::CERT_EXPIRED); |
+ https_test_server_expired.ServeFilesFromSourceDirectory( |
+ base::FilePath(kDocRoot)); |
+ ASSERT_TRUE(https_test_server_expired.Start()); |
+ |
+ content::WebContents* web_contents = |
+ browser()->tab_strip_model()->GetActiveWebContents(); |
+ SecurityStyleTestObserver observer(web_contents); |
+ |
+ // Visit a valid HTTPS url. |
+ GURL valid_https_url(https_server_.GetURL(std::string("/"))); |
+ ui_test_utils::NavigateToURL(browser(), valid_https_url); |
+ EXPECT_EQ(content::SECURITY_STYLE_AUTHENTICATED, |
+ observer.latest_security_style()); |
+ EXPECT_EQ(0u, |
+ observer.latest_explanations().unauthenticated_explanations.size()); |
+ EXPECT_EQ(0u, observer.latest_explanations().broken_explanations.size()); |
+ CheckSecureExplanations(observer.latest_explanations().secure_explanations, |
+ VALID_CERTIFICATE, browser()); |
+ EXPECT_TRUE(observer.latest_explanations().scheme_is_cryptographic); |
+ EXPECT_FALSE(observer.latest_explanations().displayed_insecure_content); |
+ EXPECT_FALSE(observer.latest_explanations().ran_insecure_content); |
+ |
+ // Navigate to a bad HTTPS page on a different host, and then click |
+ // Back to verify that the previous good security style is seen again. |
+ GURL expired_https_url(https_test_server_expired.GetURL(std::string("/"))); |
+ host_resolver()->AddRule("www.example_broken.test", "127.0.0.1"); |
+ GURL::Replacements replace_host; |
+ replace_host.SetHostStr("www.example_broken.test"); |
+ GURL https_url_different_host = |
+ expired_https_url.ReplaceComponents(replace_host); |
+ |
+ ui_test_utils::NavigateToURL(browser(), https_url_different_host); |
+ |
+ content::WaitForInterstitialAttach(web_contents); |
+ EXPECT_TRUE(web_contents->ShowingInterstitialPage()); |
+ CheckBrokenSecurityStyle(observer, net::ERR_CERT_COMMON_NAME_INVALID, |
+ browser()); |
+ ProceedThroughInterstitial(web_contents); |
+ CheckBrokenSecurityStyle(observer, net::ERR_CERT_COMMON_NAME_INVALID, |
+ browser()); |
+ CheckSecureExplanations(observer.latest_explanations().secure_explanations, |
+ INVALID_CERTIFICATE, browser()); |
+ EXPECT_TRUE(observer.latest_explanations().scheme_is_cryptographic); |
+ EXPECT_FALSE(observer.latest_explanations().displayed_insecure_content); |
+ EXPECT_FALSE(observer.latest_explanations().ran_insecure_content); |
+ |
+ content::WindowedNotificationObserver back_nav_load_observer( |
+ content::NOTIFICATION_LOAD_STOP, |
+ content::Source<content::NavigationController>( |
+ &web_contents->GetController())); |
+ chrome::GoBack(browser(), CURRENT_TAB); |
+ back_nav_load_observer.Wait(); |
+ |
+ EXPECT_EQ(content::SECURITY_STYLE_AUTHENTICATED, |
+ observer.latest_security_style()); |
+ EXPECT_EQ(0u, |
+ observer.latest_explanations().unauthenticated_explanations.size()); |
+ EXPECT_EQ(0u, observer.latest_explanations().broken_explanations.size()); |
+ CheckSecureExplanations(observer.latest_explanations().secure_explanations, |
+ VALID_CERTIFICATE, browser()); |
+ EXPECT_TRUE(observer.latest_explanations().scheme_is_cryptographic); |
+ EXPECT_FALSE(observer.latest_explanations().displayed_insecure_content); |
+ EXPECT_FALSE(observer.latest_explanations().ran_insecure_content); |
+} |
+ |
+// After AddNonsecureUrlHandler() is called, requests to this hostname |
+// will use obsolete TLS settings. |
+const char kMockNonsecureHostname[] = "example-nonsecure.test"; |
+ |
+// A URLRequestMockHTTPJob that mocks a TLS connection with an obsolete |
+// protocol version. |
+class URLRequestObsoleteTLSJob : public net::URLRequestMockHTTPJob { |
+ public: |
+ URLRequestObsoleteTLSJob(net::URLRequest* request, |
+ net::NetworkDelegate* network_delegate, |
+ const base::FilePath& file_path, |
+ scoped_refptr<net::X509Certificate> cert, |
+ scoped_refptr<base::TaskRunner> task_runner) |
+ : net::URLRequestMockHTTPJob(request, |
+ network_delegate, |
+ file_path, |
+ task_runner), |
+ cert_(std::move(cert)) {} |
+ |
+ void GetResponseInfo(net::HttpResponseInfo* info) override { |
+ net::URLRequestMockHTTPJob::GetResponseInfo(info); |
+ net::SSLConnectionStatusSetVersion(net::SSL_CONNECTION_VERSION_TLS1_1, |
+ &info->ssl_info.connection_status); |
+ const uint16_t kTlsEcdheRsaWithAes128CbcSha = 0xc013; |
+ net::SSLConnectionStatusSetCipherSuite(kTlsEcdheRsaWithAes128CbcSha, |
+ &info->ssl_info.connection_status); |
+ info->ssl_info.cert = cert_; |
+ } |
+ |
+ protected: |
+ ~URLRequestObsoleteTLSJob() override {} |
+ |
+ private: |
+ const scoped_refptr<net::X509Certificate> cert_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(URLRequestObsoleteTLSJob); |
+}; |
+ |
+// A URLRequestInterceptor that handles requests with |
+// URLRequestObsoleteTLSJob jobs. |
+class URLRequestNonsecureInterceptor : public net::URLRequestInterceptor { |
+ public: |
+ URLRequestNonsecureInterceptor( |
+ const base::FilePath& base_path, |
+ scoped_refptr<base::SequencedWorkerPool> worker_pool, |
+ scoped_refptr<net::X509Certificate> cert) |
+ : base_path_(base_path), |
+ worker_pool_(std::move(worker_pool)), |
+ cert_(std::move(cert)) {} |
+ |
+ ~URLRequestNonsecureInterceptor() override {} |
+ |
+ // net::URLRequestInterceptor: |
+ net::URLRequestJob* MaybeInterceptRequest( |
+ net::URLRequest* request, |
+ net::NetworkDelegate* network_delegate) const override { |
+ return new URLRequestObsoleteTLSJob( |
+ request, network_delegate, base_path_, cert_, |
+ worker_pool_->GetTaskRunnerWithShutdownBehavior( |
+ base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)); |
+ } |
+ |
+ private: |
+ const base::FilePath base_path_; |
+ const scoped_refptr<base::SequencedWorkerPool> worker_pool_; |
+ const scoped_refptr<net::X509Certificate> cert_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(URLRequestNonsecureInterceptor); |
+}; |
+ |
+// Installs a handler to serve HTTPS requests to |
+// |kMockNonsecureHostname| with connections that have obsolete TLS |
+// settings. |
+void AddNonsecureUrlHandler( |
+ const base::FilePath& base_path, |
+ scoped_refptr<net::X509Certificate> cert, |
+ scoped_refptr<base::SequencedWorkerPool> worker_pool) { |
+ net::URLRequestFilter* filter = net::URLRequestFilter::GetInstance(); |
+ filter->AddHostnameInterceptor( |
+ "https", kMockNonsecureHostname, |
+ std::unique_ptr<net::URLRequestInterceptor>( |
+ new URLRequestNonsecureInterceptor(base_path, worker_pool, cert))); |
+} |
+ |
+class BrowserTestNonsecureURLRequest : public InProcessBrowserTest { |
+ public: |
+ BrowserTestNonsecureURLRequest() : InProcessBrowserTest(), cert_(nullptr) {} |
+ |
+ void SetUpInProcessBrowserTestFixture() override { |
+ cert_ = |
+ net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem"); |
+ ASSERT_TRUE(cert_); |
+ } |
+ |
+ void SetUpOnMainThread() override { |
+ base::FilePath serve_file; |
+ PathService::Get(chrome::DIR_TEST_DATA, &serve_file); |
+ serve_file = serve_file.Append(FILE_PATH_LITERAL("title1.html")); |
+ content::BrowserThread::PostTask( |
+ content::BrowserThread::IO, FROM_HERE, |
+ base::Bind( |
+ &AddNonsecureUrlHandler, serve_file, cert_, |
+ make_scoped_refptr(content::BrowserThread::GetBlockingPool()))); |
+ } |
+ |
+ private: |
+ scoped_refptr<net::X509Certificate> cert_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(BrowserTestNonsecureURLRequest); |
+}; |
+ |
+// Tests that a connection with obsolete TLS settings does not get a |
+// secure connection explanation. |
+IN_PROC_BROWSER_TEST_F(BrowserTestNonsecureURLRequest, |
+ SecurityStyleChangedObserverNonsecureConnection) { |
+ content::WebContents* web_contents = |
+ browser()->tab_strip_model()->GetActiveWebContents(); |
+ SecurityStyleTestObserver observer(web_contents); |
+ |
+ ui_test_utils::NavigateToURL( |
+ browser(), GURL(std::string("https://") + kMockNonsecureHostname)); |
+ |
+ // The security style of the page doesn't get downgraded for obsolete |
+ // TLS settings, so it should remain at SECURITY_STYLE_AUTHENTICATED. |
+ EXPECT_EQ(content::SECURITY_STYLE_AUTHENTICATED, |
+ observer.latest_security_style()); |
+ |
+ // The messages explaining the security style do, however, get |
+ // downgraded: SECURE_PROTOCOL_AND_CIPHERSUITE should not show up when |
+ // the TLS settings are obsolete. |
+ for (const auto& explanation : |
+ observer.latest_explanations().secure_explanations) { |
+ EXPECT_NE(l10n_util::GetStringUTF8(IDS_SECURE_PROTOCOL_AND_CIPHERSUITE), |
+ explanation.summary); |
+ } |
+} |
+ |
} // namespace |