Add an explanation to devtools for secure connection properties

This CL adds a "secure" explanation for when an SSL connection uses
modern, secure ciphersuites and protocol versions. In the DevTools
security panel, this "secure" explanation gets displayed as a green
bullet point for correctly configured sites.

Adapts patch 1427563003 started by mmccoy@

BUG=527231

Review URL: https://codereview.chromium.org/1424903003

Cr-Commit-Position: refs/heads/master@{#356944}
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index 3b134e7..400702a 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -1395,6 +1395,14 @@
     }
   }
 
+  if (security_info.is_secure_protocol_and_ciphersuite) {
+    security_style_explanations->secure_explanations.push_back(
+        content::SecurityStyleExplanation(
+            l10n_util::GetStringUTF8(IDS_SECURE_PROTOCOL_AND_CIPHERSUITE),
+            l10n_util::GetStringUTF8(
+                IDS_SECURE_PROTOCOL_AND_CIPHERSUITE_DESCRIPTION)));
+  }
+
   return security_style;
 }
 
diff --git a/chrome/browser/ui/browser_browsertest.cc b/chrome/browser/ui/browser_browsertest.cc
index cedf67a..0da74d4e 100644
--- a/chrome/browser/ui/browser_browsertest.cc
+++ b/chrome/browser/ui/browser_browsertest.cc
@@ -51,6 +51,7 @@
 #include "chrome/browser/ui/startup/startup_browser_creator_impl.h"
 #include "chrome/browser/ui/tabs/pinned_tab_codec.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/extensions/manifest_handlers/app_launch_info.h"
 #include "chrome/common/pref_names.h"
@@ -98,7 +99,11 @@
 #include "extensions/common/extension_set.h"
 #include "net/base/net_errors.h"
 #include "net/dns/mock_host_resolver.h"
+#include "net/ssl/ssl_connection_status_flags.h"
 #include "net/test/spawned_test_server/spawned_test_server.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"
 #include "ui/base/page_transition_types.h"
 
@@ -420,19 +425,28 @@
     const std::vector<content::SecurityStyleExplanation>& secure_explanations,
     CertificateStatus cert_status,
     Browser* browser) {
-  if (cert_status != VALID_CERTIFICATE) {
-    EXPECT_EQ(0u, secure_explanations.size());
-    return;
+  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(1u, secure_explanations.size());
-  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);
 }
 
 }  // namespace
@@ -3130,6 +3144,65 @@
 }
 
 namespace {
+
+// A URLRequestMockHTTPJob that mocks an SSL connection with an
+// obsolete protocol version.
+class URLRequestNonsecureConnection : public net::URLRequestMockHTTPJob {
+ public:
+  void GetResponseInfo(net::HttpResponseInfo* info) override {
+    info->ssl_info.connection_status = (net::SSL_CONNECTION_VERSION_TLS1_1
+                                        << net::SSL_CONNECTION_VERSION_SHIFT);
+    // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 from
+    // http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-4
+    const uint16 ciphersuite = 0xc02f;
+    net::SSLConnectionStatusSetCipherSuite(ciphersuite,
+                                           &info->ssl_info.connection_status);
+  }
+
+ protected:
+  ~URLRequestNonsecureConnection() override {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(URLRequestNonsecureConnection);
+};
+
+class BrowserTestNonsecureURLRequest : public BrowserTest {
+ public:
+  BrowserTestNonsecureURLRequest() : BrowserTest() {}
+  void SetUpOnMainThread() override {
+    base::FilePath root_http;
+    PathService::Get(chrome::DIR_TEST_DATA, &root_http);
+    content::BrowserThread::PostTask(
+        content::BrowserThread::IO, FROM_HERE,
+        base::Bind(
+            &URLRequestNonsecureConnection::AddUrlHandlers, root_http,
+            make_scoped_refptr(content::BrowserThread::GetBlockingPool())));
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BrowserTestNonsecureURLRequest);
+};
+
+}  // namespace
+
+// Tests that a nonsecure connection 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(), URLRequestNonsecureConnection::GetMockHttpsUrl(std::string()));
+  for (const auto& explanation :
+       observer.latest_explanations().secure_explanations) {
+    EXPECT_NE(l10n_util::GetStringUTF8(IDS_SECURE_PROTOCOL_AND_CIPHERSUITE),
+              explanation.summary);
+  }
+}
+
+namespace {
 class JSBooleanResultGetter {
  public:
   JSBooleanResultGetter() = default;
@@ -3192,4 +3265,3 @@
 
   CheckDisplayModeMQ(ASCIIToUTF16("fullscreen"), app_contents);
 }
-
diff --git a/chrome/browser/ui/website_settings/website_settings.cc b/chrome/browser/ui/website_settings/website_settings.cc
index dbf5c85..6495c3b 100644
--- a/chrome/browser/ui/website_settings/website_settings.cc
+++ b/chrome/browser/ui/website_settings/website_settings.cc
@@ -530,10 +530,7 @@
   } else {
     site_connection_status_ = SITE_CONNECTION_STATUS_ENCRYPTED;
 
-    if (net::SSLConnectionStatusToVersion(security_info.connection_status) >=
-            net::SSL_CONNECTION_VERSION_TLS1_2 &&
-        net::IsSecureTLSCipherSuite(net::SSLConnectionStatusToCipherSuite(
-            security_info.connection_status))) {
+    if (security_info.is_secure_protocol_and_ciphersuite) {
       site_connection_details_.assign(l10n_util::GetStringFUTF16(
           IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_CONNECTION_TEXT,
           subject_name));