OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "ios/chrome/browser/ui/omnibox/page_info_model.h" |
| 6 |
| 7 #include <stdint.h> |
| 8 |
| 9 #include <string> |
| 10 |
| 11 #include "base/bind.h" |
| 12 #include "base/bind_helpers.h" |
| 13 #include "base/command_line.h" |
| 14 #include "base/i18n/time_formatting.h" |
| 15 #include "base/strings/string16.h" |
| 16 #include "base/strings/string_number_conversions.h" |
| 17 #include "base/strings/utf_string_conversions.h" |
| 18 #include "components/keyed_service/core/service_access_type.h" |
| 19 #include "components/ssl_errors/error_info.h" |
| 20 #include "components/strings/grit/components_chromium_strings.h" |
| 21 #include "components/strings/grit/components_google_chrome_strings.h" |
| 22 #include "components/strings/grit/components_strings.h" |
| 23 #include "ios/chrome/browser/browser_state/chrome_browser_state.h" |
| 24 #include "ios/chrome/browser/chrome_url_constants.h" |
| 25 #include "ios/chrome/browser/ui/omnibox/page_info_model_observer.h" |
| 26 #include "ios/chrome/grit/ios_chromium_strings.h" |
| 27 #include "ios/chrome/grit/ios_strings.h" |
| 28 #include "ios/chrome/grit/ios_theme_resources.h" |
| 29 #include "ios/web/public/ssl_status.h" |
| 30 #include "net/cert/cert_status_flags.h" |
| 31 #include "net/cert/x509_certificate.h" |
| 32 #include "net/ssl/ssl_cipher_suite_names.h" |
| 33 #include "net/ssl/ssl_connection_status_flags.h" |
| 34 #include "ui/base/l10n/l10n_util.h" |
| 35 #include "ui/base/resource/resource_bundle.h" |
| 36 |
| 37 // TODO(crbug.com/227827) Merge 178763: PageInfoModel has been removed in |
| 38 // upstream; check if we should use PageInfoModel. |
| 39 PageInfoModel::PageInfoModel(ios::ChromeBrowserState* browser_state, |
| 40 const GURL& url, |
| 41 const web::SSLStatus& ssl, |
| 42 PageInfoModelObserver* observer) |
| 43 : observer_(observer) { |
| 44 if (url.SchemeIs(kChromeUIScheme)) { |
| 45 if (url.host() == kChromeUIOfflineHost) { |
| 46 sections_.push_back(SectionInfo( |
| 47 ICON_STATE_OFFLINE_PAGE, |
| 48 l10n_util::GetStringUTF16(IDS_IOS_PAGE_INFO_OFFLINE_TITLE), |
| 49 l10n_util::GetStringUTF16(IDS_IOS_PAGE_INFO_OFFLINE_PAGE), |
| 50 SECTION_INFO_INTERNAL_PAGE, BUTTON_RELOAD)); |
| 51 } else { |
| 52 sections_.push_back( |
| 53 SectionInfo(ICON_STATE_INTERNAL_PAGE, base::string16(), |
| 54 l10n_util::GetStringUTF16(IDS_PAGE_INFO_INTERNAL_PAGE), |
| 55 SECTION_INFO_INTERNAL_PAGE, BUTTON_NONE)); |
| 56 } |
| 57 return; |
| 58 } |
| 59 |
| 60 SectionStateIcon icon_id = ICON_STATE_OK; |
| 61 base::string16 headline; |
| 62 base::string16 description; |
| 63 |
| 64 // Identity section. |
| 65 base::string16 subject_name(base::UTF8ToUTF16(url.host())); |
| 66 bool empty_subject_name = false; |
| 67 if (subject_name.empty()) { |
| 68 subject_name.assign( |
| 69 l10n_util::GetStringUTF16(IDS_PAGE_INFO_SECURITY_TAB_UNKNOWN_PARTY)); |
| 70 empty_subject_name = true; |
| 71 } |
| 72 |
| 73 bool is_cert_present = !!ssl.certificate; |
| 74 bool is_major_cert_error = net::IsCertStatusError(ssl.cert_status) && |
| 75 !net::IsCertStatusMinorError(ssl.cert_status); |
| 76 |
| 77 // It is possible to have |SECURITY_STYLE_AUTHENTICATION_BROKEN| and non-error |
| 78 // |cert_status| for WKWebView because |security_style| and |cert_status| are |
| 79 // calculated using different API, which may lead to different cert |
| 80 // verification results. |
| 81 if (is_cert_present && !is_major_cert_error && |
| 82 ssl.security_style != web::SECURITY_STYLE_AUTHENTICATION_BROKEN) { |
| 83 // There are no major errors. Check for minor errors. |
| 84 if (net::IsCertStatusMinorError(ssl.cert_status)) { |
| 85 base::string16 issuer_name( |
| 86 base::UTF8ToUTF16(ssl.certificate->issuer().GetDisplayName())); |
| 87 if (issuer_name.empty()) { |
| 88 issuer_name.assign(l10n_util::GetStringUTF16( |
| 89 IDS_PAGE_INFO_SECURITY_TAB_UNKNOWN_PARTY)); |
| 90 } |
| 91 description.assign(l10n_util::GetStringFUTF16( |
| 92 IDS_IOS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY, issuer_name)); |
| 93 |
| 94 description += base::ASCIIToUTF16("\n\n"); |
| 95 if (ssl.cert_status & net::CERT_STATUS_UNABLE_TO_CHECK_REVOCATION) { |
| 96 description += l10n_util::GetStringUTF16( |
| 97 IDS_PAGE_INFO_SECURITY_TAB_UNABLE_TO_CHECK_REVOCATION); |
| 98 } else if (ssl.cert_status & net::CERT_STATUS_NO_REVOCATION_MECHANISM) { |
| 99 description += l10n_util::GetStringUTF16( |
| 100 IDS_PAGE_INFO_SECURITY_TAB_NO_REVOCATION_MECHANISM); |
| 101 } else { |
| 102 NOTREACHED() << "Need to specify string for this warning"; |
| 103 } |
| 104 icon_id = ICON_STATE_INFO; |
| 105 } else { |
| 106 // OK HTTPS page. |
| 107 DCHECK(!(ssl.cert_status & net::CERT_STATUS_IS_EV)) |
| 108 << "Extended Validation should be disabled"; |
| 109 if (empty_subject_name) |
| 110 headline.clear(); // Don't display any title. |
| 111 else |
| 112 headline.assign(subject_name); |
| 113 base::string16 issuer_name( |
| 114 base::UTF8ToUTF16(ssl.certificate->issuer().GetDisplayName())); |
| 115 if (issuer_name.empty()) { |
| 116 issuer_name.assign(l10n_util::GetStringUTF16( |
| 117 IDS_PAGE_INFO_SECURITY_TAB_UNKNOWN_PARTY)); |
| 118 } |
| 119 description.assign(l10n_util::GetStringFUTF16( |
| 120 IDS_IOS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY, issuer_name)); |
| 121 } |
| 122 // The date after which no new SHA-1 certificates may be issued. |
| 123 // 2016-01-01 00:00:00 UTC |
| 124 // WARNING: This value must be kept in sync with WebsiteSettings::Init() in |
| 125 // chrome/browser/ui/website_settings/website_settings.cc. |
| 126 static const int64_t kJanuary2016 = INT64_C(13096080000000000); |
| 127 static const int64_t kJanuary2017 = INT64_C(13127702400000000); |
| 128 if ((ssl.cert_status & net::CERT_STATUS_SHA1_SIGNATURE_PRESENT) && |
| 129 ssl.certificate->valid_expiry() >= |
| 130 base::Time::FromInternalValue(kJanuary2016)) { |
| 131 icon_id = ICON_STATE_INFO; |
| 132 if (ssl.certificate->valid_expiry() >= |
| 133 base::Time::FromInternalValue(kJanuary2017)) { |
| 134 description += |
| 135 base::UTF8ToUTF16("\n\n") + |
| 136 l10n_util::GetStringUTF16( |
| 137 IDS_PAGE_INFO_SECURITY_TAB_DEPRECATED_SIGNATURE_ALGORITHM_MAJOR)
; |
| 138 } else { |
| 139 description += |
| 140 base::UTF8ToUTF16("\n\n") + |
| 141 l10n_util::GetStringUTF16( |
| 142 IDS_PAGE_INFO_SECURITY_TAB_DEPRECATED_SIGNATURE_ALGORITHM_MINOR)
; |
| 143 } |
| 144 } |
| 145 } else { |
| 146 // HTTP or HTTPS with errors (not warnings). |
| 147 description.assign(l10n_util::GetStringUTF16( |
| 148 IDS_PAGE_INFO_SECURITY_TAB_INSECURE_IDENTITY)); |
| 149 icon_id = ssl.security_style == web::SECURITY_STYLE_UNAUTHENTICATED |
| 150 ? ICON_NONE |
| 151 : ICON_STATE_ERROR; |
| 152 |
| 153 const base::string16 bullet = base::UTF8ToUTF16("\n • "); |
| 154 std::vector<ssl_errors::ErrorInfo> errors; |
| 155 ssl_errors::ErrorInfo::GetErrorsForCertStatus( |
| 156 ssl.certificate, ssl.cert_status, url, &errors); |
| 157 for (size_t i = 0; i < errors.size(); ++i) { |
| 158 description += bullet; |
| 159 description += errors[i].short_description(); |
| 160 } |
| 161 |
| 162 if (ssl.cert_status & net::CERT_STATUS_NON_UNIQUE_NAME) { |
| 163 description += base::ASCIIToUTF16("\n\n"); |
| 164 description += |
| 165 l10n_util::GetStringUTF16(IDS_PAGE_INFO_SECURITY_TAB_NON_UNIQUE_NAME); |
| 166 } |
| 167 } |
| 168 sections_.push_back(SectionInfo(icon_id, headline, description, |
| 169 SECTION_INFO_IDENTITY, |
| 170 BUTTON_SHOW_SECURITY_HELP)); |
| 171 |
| 172 // Connection section. |
| 173 icon_id = ICON_STATE_OK; |
| 174 headline.clear(); |
| 175 description.clear(); |
| 176 if (!ssl.certificate) { |
| 177 // Not HTTPS. |
| 178 icon_id = ssl.security_style == web::SECURITY_STYLE_UNAUTHENTICATED |
| 179 ? ICON_NONE |
| 180 : ICON_STATE_ERROR; |
| 181 description.assign(l10n_util::GetStringFUTF16( |
| 182 IDS_PAGE_INFO_SECURITY_TAB_NOT_ENCRYPTED_CONNECTION_TEXT, |
| 183 subject_name)); |
| 184 } else if (ssl.security_bits < 0) { |
| 185 if (ssl.content_status == web::SSLStatus::DISPLAYED_INSECURE_CONTENT) { |
| 186 DCHECK(description.empty()); |
| 187 // For WKWebView security_bits flag is always -1, and description is empty |
| 188 // because ciphersuite is unknown. On iOS9 WKWebView blocks active |
| 189 // mixed content, so warning should be about page look, not about page |
| 190 // behavior. |
| 191 icon_id = ICON_NONE; |
| 192 description.assign(l10n_util::GetStringUTF16( |
| 193 IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_INSECURE_CONTENT_WARNING)); |
| 194 } else { |
| 195 // Security strength is unknown. Say nothing. |
| 196 icon_id = ICON_STATE_ERROR; |
| 197 } |
| 198 } else if (ssl.security_bits == 0) { |
| 199 DCHECK_NE(ssl.security_style, web::SECURITY_STYLE_UNAUTHENTICATED); |
| 200 icon_id = ICON_STATE_ERROR; |
| 201 description.assign(l10n_util::GetStringFUTF16( |
| 202 IDS_PAGE_INFO_SECURITY_TAB_NOT_ENCRYPTED_CONNECTION_TEXT, |
| 203 subject_name)); |
| 204 } else { |
| 205 if (net::SSLConnectionStatusToVersion(ssl.connection_status) >= |
| 206 net::SSL_CONNECTION_VERSION_TLS1_2 && |
| 207 (net::OBSOLETE_SSL_NONE == |
| 208 net::ObsoleteSSLStatus( |
| 209 net::SSLConnectionStatusToCipherSuite(ssl.connection_status)))) { |
| 210 description.assign(l10n_util::GetStringFUTF16( |
| 211 IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_CONNECTION_TEXT, subject_name)); |
| 212 } else { |
| 213 description.assign(l10n_util::GetStringFUTF16( |
| 214 IDS_PAGE_INFO_SECURITY_TAB_WEAK_ENCRYPTION_CONNECTION_TEXT, |
| 215 subject_name)); |
| 216 } |
| 217 if (ssl.content_status) { |
| 218 bool ran_insecure_content = false; // Always false on iOS. |
| 219 icon_id = ran_insecure_content ? ICON_STATE_ERROR : ICON_NONE; |
| 220 description.assign(l10n_util::GetStringFUTF16( |
| 221 IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_SENTENCE_LINK, description, |
| 222 l10n_util::GetStringUTF16( |
| 223 ran_insecure_content |
| 224 ? IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_INSECURE_CONTENT_ERROR |
| 225 : IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_INSECURE_CONTENT_WARNIN
G))); |
| 226 } |
| 227 } |
| 228 |
| 229 uint16_t cipher_suite = |
| 230 net::SSLConnectionStatusToCipherSuite(ssl.connection_status); |
| 231 if (ssl.security_bits > 0 && cipher_suite) { |
| 232 int ssl_version = net::SSLConnectionStatusToVersion(ssl.connection_status); |
| 233 const char* ssl_version_str; |
| 234 net::SSLVersionToString(&ssl_version_str, ssl_version); |
| 235 description += base::ASCIIToUTF16("\n\n"); |
| 236 description += |
| 237 l10n_util::GetStringFUTF16(IDS_PAGE_INFO_SECURITY_TAB_SSL_VERSION, |
| 238 base::ASCIIToUTF16(ssl_version_str)); |
| 239 |
| 240 bool no_renegotiation = |
| 241 (ssl.connection_status & |
| 242 net::SSL_CONNECTION_NO_RENEGOTIATION_EXTENSION) != 0; |
| 243 const char *key_exchange, *cipher, *mac; |
| 244 bool is_aead; |
| 245 bool is_tls13; |
| 246 net::SSLCipherSuiteToStrings(&key_exchange, &cipher, &mac, &is_aead, |
| 247 &is_tls13, cipher_suite); |
| 248 |
| 249 description += base::ASCIIToUTF16("\n\n"); |
| 250 if (is_aead) { |
| 251 description += l10n_util::GetStringFUTF16( |
| 252 IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTION_DETAILS_AEAD, |
| 253 base::ASCIIToUTF16(cipher), base::ASCIIToUTF16(key_exchange)); |
| 254 } else { |
| 255 description += l10n_util::GetStringFUTF16( |
| 256 IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTION_DETAILS, |
| 257 base::ASCIIToUTF16(cipher), base::ASCIIToUTF16(mac), |
| 258 base::ASCIIToUTF16(key_exchange)); |
| 259 } |
| 260 |
| 261 if (no_renegotiation) { |
| 262 description += base::ASCIIToUTF16("\n\n"); |
| 263 description += l10n_util::GetStringUTF16( |
| 264 IDS_PAGE_INFO_SECURITY_TAB_RENEGOTIATION_MESSAGE); |
| 265 } |
| 266 } |
| 267 |
| 268 if (!description.empty()) { |
| 269 sections_.push_back(SectionInfo(icon_id, headline, description, |
| 270 SECTION_INFO_CONNECTION, |
| 271 BUTTON_SHOW_SECURITY_HELP)); |
| 272 } |
| 273 |
| 274 if (ssl.certificate) { |
| 275 certificate_label_ = |
| 276 l10n_util::GetStringUTF16(IDS_PAGEINFO_CERT_INFO_BUTTON); |
| 277 } |
| 278 } |
| 279 |
| 280 PageInfoModel::~PageInfoModel() {} |
| 281 |
| 282 int PageInfoModel::GetSectionCount() { |
| 283 return sections_.size(); |
| 284 } |
| 285 |
| 286 PageInfoModel::SectionInfo PageInfoModel::GetSectionInfo(int index) { |
| 287 DCHECK(index < static_cast<int>(sections_.size())); |
| 288 return sections_[index]; |
| 289 } |
| 290 |
| 291 gfx::Image* PageInfoModel::GetIconImage(SectionStateIcon icon_id) { |
| 292 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
| 293 switch (icon_id) { |
| 294 case ICON_NONE: |
| 295 case ICON_STATE_INTERNAL_PAGE: |
| 296 return nullptr; |
| 297 case ICON_STATE_OK: |
| 298 return &rb.GetNativeImageNamed(IDR_IOS_PAGEINFO_GOOD); |
| 299 case ICON_STATE_ERROR: |
| 300 return &rb.GetNativeImageNamed(IDR_IOS_PAGEINFO_BAD); |
| 301 case ICON_STATE_INFO: |
| 302 return &rb.GetNativeImageNamed(IDR_IOS_PAGEINFO_INFO); |
| 303 case ICON_STATE_OFFLINE_PAGE: |
| 304 return &rb.GetNativeImageNamed(IDR_IOS_OMNIBOX_OFFLINE); |
| 305 } |
| 306 } |
| 307 |
| 308 base::string16 PageInfoModel::GetCertificateLabel() const { |
| 309 return certificate_label_; |
| 310 } |
| 311 |
| 312 PageInfoModel::PageInfoModel() : observer_(NULL) {} |
OLD | NEW |