Refactor WebsiteSettings to operate on a SecurityInfo

Previously, WebsiteSettings operated on a content::SSLStatus. This gave
us no convenient place to share policies and calculations that
WebsiteSettings shared with other //chrome security UI elements: for
example, SHA1 deprecation and ChromeOS policy certs.

This CL refactors WebsiteSettings to operate on a
SecurityStateModel::SecurityInfo instead of a content::SSLStatus. The
SecurityInfo object already contains information about, for example,
SHA1 deprecation, so that WebsiteSettings doesn't have to compute that
on its own.

BUG=528034

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

Cr-Commit-Position: refs/heads/master@{#349772}
diff --git a/chrome/browser/ui/website_settings/website_settings.cc b/chrome/browser/ui/website_settings/website_settings.cc
index 4c1391a4..52b6925 100644
--- a/chrome/browser/ui/website_settings/website_settings.cc
+++ b/chrome/browser/ui/website_settings/website_settings.cc
@@ -46,7 +46,6 @@
 #include "content/public/browser/cert_store.h"
 #include "content/public/browser/user_metrics.h"
 #include "content/public/common/content_switches.h"
-#include "content/public/common/ssl_status.h"
 #include "content/public/common/url_constants.h"
 #include "net/cert/cert_status_flags.h"
 #include "net/cert/x509_certificate.h"
@@ -99,32 +98,30 @@
 };
 
 bool CertificateTransparencyStatusMatch(
-    const content::SignedCertificateTimestampIDStatusList& scts,
+    const std::vector<net::ct::SCTVerifyStatus>& sct_verify_statuses,
     net::ct::SCTVerifyStatus status) {
-  for (content::SignedCertificateTimestampIDStatusList::const_iterator it =
-           scts.begin();
-       it != scts.end();
-       ++it) {
-    if (it->status == status)
+  for (const auto& verify_status : sct_verify_statuses) {
+    if (verify_status == status)
       return true;
   }
-
   return false;
 }
 
 int GetSiteIdentityDetailsMessageByCTInfo(
-    const content::SignedCertificateTimestampIDStatusList& scts,
+    const std::vector<net::ct::SCTVerifyStatus>& sct_verify_statuses,
     bool is_ev) {
   // No SCTs - no CT information.
-  if (scts.empty())
+  if (sct_verify_statuses.empty())
     return (is_ev ? IDS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY_EV_NO_CT
                   : IDS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY_NO_CT);
 
-  if (CertificateTransparencyStatusMatch(scts, net::ct::SCT_STATUS_OK))
+  if (CertificateTransparencyStatusMatch(sct_verify_statuses,
+                                         net::ct::SCT_STATUS_OK))
     return (is_ev ? IDS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY_EV_CT_VERIFIED
                   : IDS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY_CT_VERIFIED);
 
-  if (CertificateTransparencyStatusMatch(scts, net::ct::SCT_STATUS_INVALID))
+  if (CertificateTransparencyStatusMatch(sct_verify_statuses,
+                                         net::ct::SCT_STATUS_INVALID))
     return (is_ev ? IDS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY_EV_CT_INVALID
                   : IDS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY_CT_INVALID);
 
@@ -138,9 +135,10 @@
 // which failed verification, in which case it will return
 // SITE_IDENTITY_STATUS_ERROR.
 WebsiteSettings::SiteIdentityStatus GetSiteIdentityStatusByCTInfo(
-    const content::SignedCertificateTimestampIDStatusList& scts,
+    const std::vector<net::ct::SCTVerifyStatus>& sct_verify_statuses,
     bool is_ev) {
-  if (CertificateTransparencyStatusMatch(scts, net::ct::SCT_STATUS_INVALID))
+  if (CertificateTransparencyStatusMatch(sct_verify_statuses,
+                                         net::ct::SCT_STATUS_INVALID))
     return WebsiteSettings::SITE_IDENTITY_STATUS_ERROR;
 
   return is_ev ? WebsiteSettings::SITE_IDENTITY_STATUS_EV_CERT
@@ -162,7 +160,7 @@
     TabSpecificContentSettings* tab_specific_content_settings,
     content::WebContents* web_contents,
     const GURL& url,
-    const content::SSLStatus& ssl,
+    const SecurityStateModel::SecurityInfo& security_info,
     content::CertStore* cert_store)
     : TabSpecificContentSettings::SiteDataObserver(
           tab_specific_content_settings),
@@ -179,7 +177,7 @@
           ChromeSSLHostStateDelegateFactory::GetForProfile(profile)),
       did_revoke_user_ssl_decisions_(false),
       profile_(profile) {
-  Init(url, ssl);
+  Init(url, security_info);
 
   PresentSitePermissions();
   PresentSiteData();
@@ -356,7 +354,9 @@
   did_revoke_user_ssl_decisions_ = true;
 }
 
-void WebsiteSettings::Init(const GURL& url, const content::SSLStatus& ssl) {
+void WebsiteSettings::Init(
+    const GURL& url,
+    const SecurityStateModel::SecurityInfo& security_info) {
   bool isChromeUINativeScheme = false;
 #if defined(OS_ANDROID)
   isChromeUINativeScheme = url.SchemeIs(chrome::kChromeUINativeScheme);
@@ -373,25 +373,20 @@
 
   // Identity section.
   scoped_refptr<net::X509Certificate> cert;
-  cert_id_ = ssl.cert_id;
+  cert_id_ = security_info.cert_id;
 
-  if (ssl.cert_id &&
-      cert_store_->RetrieveCert(ssl.cert_id, &cert) &&
-      (!net::IsCertStatusError(ssl.cert_status) ||
-       net::IsCertStatusMinorError(ssl.cert_status))) {
+  // HTTPS with no or minor errors.
+  if (security_info.cert_id &&
+      cert_store_->RetrieveCert(security_info.cert_id, &cert) &&
+      (!net::IsCertStatusError(security_info.cert_status) ||
+       net::IsCertStatusMinorError(security_info.cert_status))) {
     // There are no major errors. Check for minor errors.
-#if defined(OS_CHROMEOS)
-    policy::PolicyCertService* service =
-        policy::PolicyCertServiceFactory::GetForProfile(profile_);
-    const bool used_policy_certs = service && service->UsedPolicyCertificates();
-#else
-    const bool used_policy_certs = false;
-#endif
-    if (used_policy_certs) {
+    if (security_info.security_level ==
+        SecurityStateModel::SECURITY_POLICY_WARNING) {
       site_identity_status_ = SITE_IDENTITY_STATUS_ADMIN_PROVIDED_CERT;
       site_identity_details_ = l10n_util::GetStringFUTF16(
           IDS_CERT_POLICY_PROVIDED_CERT_MESSAGE, UTF8ToUTF16(url.host()));
-    } else if (net::IsCertStatusMinorError(ssl.cert_status)) {
+    } else if (net::IsCertStatusMinorError(security_info.cert_status)) {
       site_identity_status_ = SITE_IDENTITY_STATUS_CERT_REVOCATION_UNKNOWN;
       base::string16 issuer_name(UTF8ToUTF16(cert->issuer().GetDisplayName()));
       if (issuer_name.empty()) {
@@ -401,24 +396,26 @@
 
       site_identity_details_.assign(l10n_util::GetStringFUTF16(
           GetSiteIdentityDetailsMessageByCTInfo(
-              ssl.signed_certificate_timestamp_ids, false /* not EV */),
+              security_info.sct_verify_statuses, false /* not EV */),
           issuer_name));
 
       site_identity_details_ += ASCIIToUTF16("\n\n");
-      if (ssl.cert_status & net::CERT_STATUS_UNABLE_TO_CHECK_REVOCATION) {
+      if (security_info.cert_status &
+          net::CERT_STATUS_UNABLE_TO_CHECK_REVOCATION) {
         site_identity_details_ += l10n_util::GetStringUTF16(
             IDS_PAGE_INFO_SECURITY_TAB_UNABLE_TO_CHECK_REVOCATION);
-      } else if (ssl.cert_status & net::CERT_STATUS_NO_REVOCATION_MECHANISM) {
+      } else if (security_info.cert_status &
+                 net::CERT_STATUS_NO_REVOCATION_MECHANISM) {
         site_identity_details_ += l10n_util::GetStringUTF16(
             IDS_PAGE_INFO_SECURITY_TAB_NO_REVOCATION_MECHANISM);
       } else {
         NOTREACHED() << "Need to specify string for this warning";
       }
     } else {
-      if (ssl.cert_status & net::CERT_STATUS_IS_EV) {
+      if (security_info.cert_status & net::CERT_STATUS_IS_EV) {
         // EV HTTPS page.
         site_identity_status_ = GetSiteIdentityStatusByCTInfo(
-            ssl.signed_certificate_timestamp_ids, true);
+            security_info.sct_verify_statuses, true);
         DCHECK(!cert->subject().organization_names.empty());
         organization_name_ = UTF8ToUTF16(cert->subject().organization_names[0]);
         // An EV Cert is required to have a city (localityName) and country but
@@ -441,14 +438,13 @@
         DCHECK(!cert->subject().organization_names.empty());
         site_identity_details_.assign(l10n_util::GetStringFUTF16(
             GetSiteIdentityDetailsMessageByCTInfo(
-                ssl.signed_certificate_timestamp_ids, true /* is EV */),
-            UTF8ToUTF16(cert->subject().organization_names[0]),
-            locality,
+                security_info.sct_verify_statuses, true /* is EV */),
+            UTF8ToUTF16(cert->subject().organization_names[0]), locality,
             UTF8ToUTF16(cert->issuer().GetDisplayName())));
       } else {
         // Non-EV OK HTTPS page.
         site_identity_status_ = GetSiteIdentityStatusByCTInfo(
-            ssl.signed_certificate_timestamp_ids, false);
+            security_info.sct_verify_statuses, false);
         base::string16 issuer_name(
             UTF8ToUTF16(cert->issuer().GetDisplayName()));
         if (issuer_name.empty()) {
@@ -458,15 +454,11 @@
 
         site_identity_details_.assign(l10n_util::GetStringFUTF16(
             GetSiteIdentityDetailsMessageByCTInfo(
-                ssl.signed_certificate_timestamp_ids, false /* not EV */),
+                security_info.sct_verify_statuses, false /* not EV */),
             issuer_name));
       }
-      // The date after which no new SHA-1 certificates may be issued.
-      // 2016-01-01 00:00:00 UTC
-      static const int64_t kSHA1LastIssuanceDate = INT64_C(13096080000000000);
-      if ((ssl.cert_status & net::CERT_STATUS_SHA1_SIGNATURE_PRESENT) &&
-          cert->valid_expiry() >
-              base::Time::FromInternalValue(kSHA1LastIssuanceDate)) {
+      if (security_info.sha1_deprecation_status !=
+          SecurityStateModel::NO_DEPRECATED_SHA1) {
         site_identity_status_ =
             SITE_IDENTITY_STATUS_DEPRECATED_SIGNATURE_ALGORITHM;
         site_identity_details_ +=
@@ -479,21 +471,21 @@
     // HTTP or HTTPS with errors (not warnings).
     site_identity_details_.assign(l10n_util::GetStringUTF16(
         IDS_PAGE_INFO_SECURITY_TAB_INSECURE_IDENTITY));
-    if (ssl.security_style == content::SECURITY_STYLE_UNAUTHENTICATED)
+    if (!security_info.scheme_is_cryptographic || !security_info.cert_id)
       site_identity_status_ = SITE_IDENTITY_STATUS_NO_CERT;
     else
       site_identity_status_ = SITE_IDENTITY_STATUS_ERROR;
 
     const base::string16 bullet = UTF8ToUTF16("\n • ");
     std::vector<ssl_errors::ErrorInfo> errors;
-    ssl_errors::ErrorInfo::GetErrorsForCertStatus(cert, ssl.cert_status, url,
-                                                  &errors);
+    ssl_errors::ErrorInfo::GetErrorsForCertStatus(
+        cert, security_info.cert_status, url, &errors);
     for (size_t i = 0; i < errors.size(); ++i) {
       site_identity_details_ += bullet;
       site_identity_details_ += errors[i].short_description();
     }
 
-    if (ssl.cert_status & net::CERT_STATUS_NON_UNIQUE_NAME) {
+    if (security_info.cert_status & net::CERT_STATUS_NON_UNIQUE_NAME) {
       site_identity_details_ += ASCIIToUTF16("\n\n");
       site_identity_details_ += l10n_util::GetStringUTF16(
           IDS_PAGE_INFO_SECURITY_TAB_NON_UNIQUE_NAME);
@@ -512,27 +504,19 @@
         l10n_util::GetStringUTF16(IDS_PAGE_INFO_SECURITY_TAB_UNKNOWN_PARTY));
   }
 
-  if (ssl.security_style == content::SECURITY_STYLE_UNKNOWN) {
-    // Page is still loading, so SSL status is not yet available. Say nothing.
-    DCHECK_EQ(ssl.security_bits, -1);
+  if (!security_info.cert_id || !security_info.scheme_is_cryptographic) {
+    // Page is still loading (so SSL status is not yet available) or
+    // loaded over HTTP or loaded over HTTPS with no cert.
     site_connection_status_ = SITE_CONNECTION_STATUS_UNENCRYPTED;
 
     site_connection_details_.assign(l10n_util::GetStringFUTF16(
         IDS_PAGE_INFO_SECURITY_TAB_NOT_ENCRYPTED_CONNECTION_TEXT,
         subject_name));
-  } else if (ssl.security_style == content::SECURITY_STYLE_UNAUTHENTICATED) {
-    // HTTPS without a certificate, or not HTTPS.
-    DCHECK(!ssl.cert_id);
-    site_connection_status_ = SITE_CONNECTION_STATUS_UNENCRYPTED;
-
-    site_connection_details_.assign(l10n_util::GetStringFUTF16(
-        IDS_PAGE_INFO_SECURITY_TAB_NOT_ENCRYPTED_CONNECTION_TEXT,
-        subject_name));
-  } else if (ssl.security_bits < 0) {
-    // Security strength is unknown. Say nothing.
+  } else if (security_info.security_bits < 0) {
+    // Security strength is unknown.  Say nothing.
     site_connection_status_ = SITE_CONNECTION_STATUS_ENCRYPTED_ERROR;
-  } else if (ssl.security_bits == 0) {
-    DCHECK_NE(ssl.security_style, content::SECURITY_STYLE_UNAUTHENTICATED);
+  } else if (security_info.security_bits == 0) {
+    DCHECK_NE(security_info.security_level, SecurityStateModel::NONE);
     site_connection_status_ = SITE_CONNECTION_STATUS_ENCRYPTED_ERROR;
     site_connection_details_.assign(l10n_util::GetStringFUTF16(
         IDS_PAGE_INFO_SECURITY_TAB_NOT_ENCRYPTED_CONNECTION_TEXT,
@@ -540,10 +524,10 @@
   } else {
     site_connection_status_ = SITE_CONNECTION_STATUS_ENCRYPTED;
 
-    if (net::SSLConnectionStatusToVersion(ssl.connection_status) >=
+    if (net::SSLConnectionStatusToVersion(security_info.connection_status) >=
             net::SSL_CONNECTION_VERSION_TLS1_2 &&
-        net::IsSecureTLSCipherSuite(
-            net::SSLConnectionStatusToCipherSuite(ssl.connection_status))) {
+        net::IsSecureTLSCipherSuite(net::SSLConnectionStatusToCipherSuite(
+            security_info.connection_status))) {
       site_connection_details_.assign(l10n_util::GetStringFUTF16(
           IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_CONNECTION_TEXT,
           subject_name));
@@ -553,9 +537,13 @@
           subject_name));
     }
 
-    if (ssl.content_status) {
+    if (security_info.mixed_content_status !=
+        SecurityStateModel::NO_MIXED_CONTENT) {
       bool ran_insecure_content =
-          !!(ssl.content_status & content::SSLStatus::RAN_INSECURE_CONTENT);
+          (security_info.mixed_content_status ==
+               SecurityStateModel::RAN_MIXED_CONTENT ||
+           security_info.mixed_content_status ==
+               SecurityStateModel::RAN_AND_DISPLAYED_MIXED_CONTENT);
       site_connection_status_ = ran_insecure_content
                                     ? SITE_CONNECTION_STATUS_MIXED_SCRIPT
                                     : SITE_CONNECTION_STATUS_MIXED_CONTENT;
@@ -569,10 +557,10 @@
   }
 
   uint16 cipher_suite =
-      net::SSLConnectionStatusToCipherSuite(ssl.connection_status);
-  if (ssl.security_bits > 0 && cipher_suite) {
+      net::SSLConnectionStatusToCipherSuite(security_info.connection_status);
+  if (security_info.security_bits > 0 && cipher_suite) {
     int ssl_version =
-        net::SSLConnectionStatusToVersion(ssl.connection_status);
+        net::SSLConnectionStatusToVersion(security_info.connection_status);
     const char* ssl_version_str;
     net::SSLVersionToString(&ssl_version_str, ssl_version);
     site_connection_details_ += ASCIIToUTF16("\n\n");
@@ -581,8 +569,8 @@
         ASCIIToUTF16(ssl_version_str));
 
     bool no_renegotiation =
-        (ssl.connection_status &
-        net::SSL_CONNECTION_NO_RENEGOTIATION_EXTENSION) != 0;
+        (security_info.connection_status &
+         net::SSL_CONNECTION_NO_RENEGOTIATION_EXTENSION) != 0;
     const char *key_exchange, *cipher, *mac;
     bool is_aead;
     net::SSLCipherSuiteToStrings(
@@ -604,8 +592,8 @@
       site_connection_status_ = SITE_CONNECTION_STATUS_ENCRYPTED_ERROR;
     }
 
-    const bool did_fallback =
-        (ssl.connection_status & net::SSL_CONNECTION_VERSION_FALLBACK) != 0;
+    const bool did_fallback = (security_info.connection_status &
+                               net::SSL_CONNECTION_VERSION_FALLBACK) != 0;
     if (did_fallback) {
       site_connection_details_ += ASCIIToUTF16("\n\n");
       site_connection_details_ += l10n_util::GetStringUTF16(