| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "components/ssl_errors/error_classification.h" | 5 #include "components/ssl_errors/error_classification.h" |
| 6 | 6 |
| 7 #include <limits.h> | 7 #include <limits.h> |
| 8 #include <stddef.h> | 8 #include <stddef.h> |
| 9 | 9 |
| 10 #include <vector> | 10 #include <vector> |
| 11 | 11 |
| 12 #include "base/build_time.h" | 12 #include "base/build_time.h" |
| 13 #include "base/lazy_instance.h" | 13 #include "base/lazy_instance.h" |
| 14 #include "base/metrics/histogram_macros.h" | 14 #include "base/metrics/histogram_macros.h" |
| 15 #include "base/strings/string_split.h" | 15 #include "base/strings/string_split.h" |
| 16 #include "base/strings/utf_string_conversions.h" | 16 #include "base/strings/utf_string_conversions.h" |
| 17 #include "base/time/time.h" | 17 #include "base/time/time.h" |
| 18 #include "build/build_config.h" | 18 #include "build/build_config.h" |
| 19 #include "components/network_time/network_time_tracker.h" |
| 19 #include "components/ssl_errors/error_info.h" | 20 #include "components/ssl_errors/error_info.h" |
| 20 #include "components/url_formatter/url_formatter.h" | 21 #include "components/url_formatter/url_formatter.h" |
| 21 #include "net/base/network_change_notifier.h" | 22 #include "net/base/network_change_notifier.h" |
| 22 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" | 23 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" |
| 23 #include "net/base/url_util.h" | 24 #include "net/base/url_util.h" |
| 24 #include "net/cert/x509_cert_types.h" | 25 #include "net/cert/x509_cert_types.h" |
| 25 #include "net/cert/x509_certificate.h" | 26 #include "net/cert/x509_certificate.h" |
| 26 #include "url/gurl.h" | 27 #include "url/gurl.h" |
| 27 | 28 |
| 28 #if defined(OS_WIN) | 29 #if defined(OS_WIN) |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 110 std::vector<std::string> dns_names; | 111 std::vector<std::string> dns_names; |
| 111 cert.GetDNSNames(&dns_names); | 112 cert.GetDNSNames(&dns_names); |
| 112 return GetWWWSubDomainMatch(request_url, dns_names, &www_host); | 113 return GetWWWSubDomainMatch(request_url, dns_names, &www_host); |
| 113 } | 114 } |
| 114 | 115 |
| 115 // The time to use when doing build time operations in browser tests. | 116 // The time to use when doing build time operations in browser tests. |
| 116 base::LazyInstance<base::Time> g_testing_build_time = LAZY_INSTANCE_INITIALIZER; | 117 base::LazyInstance<base::Time> g_testing_build_time = LAZY_INSTANCE_INITIALIZER; |
| 117 | 118 |
| 118 } // namespace | 119 } // namespace |
| 119 | 120 |
| 121 static ssl_errors::ErrorInfo::ErrorType RecordErrorType(int cert_error) { |
| 122 ssl_errors::ErrorInfo::ErrorType error_type = |
| 123 ssl_errors::ErrorInfo::NetErrorToErrorType(cert_error); |
| 124 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl_error_type", error_type, |
| 125 ssl_errors::ErrorInfo::END_OF_ENUM); |
| 126 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.connection_type", |
| 127 net::NetworkChangeNotifier::GetConnectionType(), |
| 128 net::NetworkChangeNotifier::CONNECTION_LAST); |
| 129 return error_type; |
| 130 } |
| 131 |
| 120 void RecordUMAStatistics(bool overridable, | 132 void RecordUMAStatistics(bool overridable, |
| 121 const base::Time& current_time, | 133 const base::Time& current_time, |
| 122 const GURL& request_url, | 134 const GURL& request_url, |
| 123 int cert_error, | 135 int cert_error, |
| 124 const net::X509Certificate& cert) { | 136 const net::X509Certificate& cert) { |
| 125 ssl_errors::ErrorInfo::ErrorType type = | 137 ssl_errors::ErrorInfo::ErrorType error_type = RecordErrorType(cert_error); |
| 126 ssl_errors::ErrorInfo::NetErrorToErrorType(cert_error); | 138 |
| 127 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl_error_type", type, | 139 switch (error_type) { |
| 128 ssl_errors::ErrorInfo::END_OF_ENUM); | |
| 129 switch (type) { | |
| 130 case ssl_errors::ErrorInfo::CERT_DATE_INVALID: { | 140 case ssl_errors::ErrorInfo::CERT_DATE_INVALID: { |
| 131 if (IsUserClockInThePast(base::Time::NowFromSystemTime())) { | 141 // Note: not reached when displaying the bad clock interstitial. |
| 132 RecordSSLInterstitialCause(overridable, CLOCK_PAST); | 142 // See |RecordUMAStatisticsForClockInterstitial| below. |
| 133 } else if (IsUserClockInTheFuture(base::Time::NowFromSystemTime())) { | 143 if (cert.HasExpired() && |
| 134 RecordSSLInterstitialCause(overridable, CLOCK_FUTURE); | 144 (current_time - cert.valid_expiry()).InDays() < 28) { |
| 135 } else if (cert.HasExpired() && | |
| 136 (current_time - cert.valid_expiry()).InDays() < 28) { | |
| 137 RecordSSLInterstitialCause(overridable, EXPIRED_RECENTLY); | 145 RecordSSLInterstitialCause(overridable, EXPIRED_RECENTLY); |
| 138 } | 146 } |
| 139 break; | 147 break; |
| 140 } | 148 } |
| 141 case ssl_errors::ErrorInfo::CERT_COMMON_NAME_INVALID: { | 149 case ssl_errors::ErrorInfo::CERT_COMMON_NAME_INVALID: { |
| 142 std::string host_name = request_url.host(); | 150 std::string host_name = request_url.host(); |
| 143 if (IsHostNameKnownTLD(host_name)) { | 151 if (IsHostNameKnownTLD(host_name)) { |
| 144 HostnameTokens host_name_tokens = Tokenize(host_name); | 152 HostnameTokens host_name_tokens = Tokenize(host_name); |
| 145 if (IsWWWSubDomainMatch(request_url, cert)) | 153 if (IsWWWSubDomainMatch(request_url, cert)) |
| 146 RecordSSLInterstitialCause(overridable, WWW_SUBDOMAIN_MATCH); | 154 RecordSSLInterstitialCause(overridable, WWW_SUBDOMAIN_MATCH); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 169 RecordSSLInterstitialCause(overridable, LOCALHOST); | 177 RecordSSLInterstitialCause(overridable, LOCALHOST); |
| 170 if (IsHostnameNonUniqueOrDotless(hostname)) | 178 if (IsHostnameNonUniqueOrDotless(hostname)) |
| 171 RecordSSLInterstitialCause(overridable, PRIVATE_URL); | 179 RecordSSLInterstitialCause(overridable, PRIVATE_URL); |
| 172 if (net::X509Certificate::IsSelfSigned(cert.os_cert_handle())) | 180 if (net::X509Certificate::IsSelfSigned(cert.os_cert_handle())) |
| 173 RecordSSLInterstitialCause(overridable, SELF_SIGNED); | 181 RecordSSLInterstitialCause(overridable, SELF_SIGNED); |
| 174 break; | 182 break; |
| 175 } | 183 } |
| 176 default: | 184 default: |
| 177 break; | 185 break; |
| 178 } | 186 } |
| 179 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.connection_type", | |
| 180 net::NetworkChangeNotifier::GetConnectionType(), | |
| 181 net::NetworkChangeNotifier::CONNECTION_LAST); | |
| 182 } | 187 } |
| 183 | 188 |
| 184 bool IsUserClockInThePast(const base::Time& time_now) { | 189 void RecordUMAStatisticsForClockInterstitial(bool overridable, |
| 185 base::Time build_time; | 190 ssl_errors::ClockState clock_state, |
| 186 if (!g_testing_build_time.Get().is_null()) { | 191 int cert_error) { |
| 187 build_time = g_testing_build_time.Get(); | 192 ssl_errors::ErrorInfo::ErrorType error_type = RecordErrorType(cert_error); |
| 193 DCHECK(error_type == ssl_errors::ErrorInfo::CERT_DATE_INVALID); |
| 194 |
| 195 if (clock_state == ssl_errors::CLOCK_STATE_FUTURE) { |
| 196 RecordSSLInterstitialCause(overridable, CLOCK_FUTURE); |
| 197 } else if (clock_state == ssl_errors::CLOCK_STATE_PAST) { |
| 198 RecordSSLInterstitialCause(overridable, CLOCK_PAST); |
| 188 } else { | 199 } else { |
| 189 build_time = base::GetBuildTime(); | 200 NOTREACHED(); |
| 201 } |
| 202 } |
| 203 |
| 204 ClockState GetClockState( |
| 205 const base::Time& now_system, |
| 206 const network_time::NetworkTimeTracker* network_time_tracker) { |
| 207 base::Time now_network; |
| 208 base::TimeDelta uncertainty; |
| 209 const base::TimeDelta kNetworkTimeFudge = base::TimeDelta::FromMinutes(5); |
| 210 ClockState network_state = CLOCK_STATE_UNKNOWN; |
| 211 if (network_time_tracker->GetNetworkTime(&now_network, &uncertainty)) { |
| 212 if (now_system < now_network - uncertainty - kNetworkTimeFudge) { |
| 213 network_state = CLOCK_STATE_PAST; |
| 214 } else if (now_system > now_network + uncertainty + kNetworkTimeFudge) { |
| 215 network_state = CLOCK_STATE_FUTURE; |
| 216 } else { |
| 217 network_state = CLOCK_STATE_OK; |
| 218 } |
| 190 } | 219 } |
| 191 | 220 |
| 192 if (time_now < build_time - base::TimeDelta::FromDays(2)) | 221 ClockState build_time_state = CLOCK_STATE_UNKNOWN; |
| 193 return true; | 222 base::Time build_time = g_testing_build_time.Get().is_null() |
| 194 return false; | 223 ? base::GetBuildTime() |
| 195 } | 224 : g_testing_build_time.Get(); |
| 196 | 225 if (now_system < build_time - base::TimeDelta::FromDays(2)) { |
| 197 bool IsUserClockInTheFuture(const base::Time& time_now) { | 226 build_time_state = CLOCK_STATE_PAST; |
| 198 base::Time build_time; | 227 } else if (now_system > build_time + base::TimeDelta::FromDays(365)) { |
| 199 if (!g_testing_build_time.Get().is_null()) { | 228 build_time_state = CLOCK_STATE_FUTURE; |
| 200 build_time = g_testing_build_time.Get(); | |
| 201 } else { | |
| 202 build_time = base::GetBuildTime(); | |
| 203 } | 229 } |
| 204 | 230 |
| 205 if (time_now > build_time + base::TimeDelta::FromDays(365)) | 231 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.clockstate.network", |
| 206 return true; | 232 network_state, CLOCK_STATE_MAX); |
| 207 return false; | 233 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.clockstate.build_time", |
| 234 build_time_state, CLOCK_STATE_MAX); |
| 235 |
| 236 return network_state == CLOCK_STATE_UNKNOWN ? build_time_state |
| 237 : network_state; |
| 208 } | 238 } |
| 209 | 239 |
| 210 void SetBuildTimeForTesting(const base::Time& testing_time) { | 240 void SetBuildTimeForTesting(const base::Time& testing_time) { |
| 211 g_testing_build_time.Get() = testing_time; | 241 g_testing_build_time.Get() = testing_time; |
| 212 } | 242 } |
| 213 | 243 |
| 214 bool IsHostNameKnownTLD(const std::string& host_name) { | 244 bool IsHostNameKnownTLD(const std::string& host_name) { |
| 215 size_t tld_length = net::registry_controlled_domains::GetRegistryLength( | 245 size_t tld_length = net::registry_controlled_domains::GetRegistryLength( |
| 216 host_name, net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES, | 246 host_name, net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES, |
| 217 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); | 247 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 412 return std::find(dns_names_domain.begin(), dns_names_domain.end() - 1, | 442 return std::find(dns_names_domain.begin(), dns_names_domain.end() - 1, |
| 413 host_name_domain) != dns_names_domain.end() - 1; | 443 host_name_domain) != dns_names_domain.end() - 1; |
| 414 } | 444 } |
| 415 | 445 |
| 416 bool IsHostnameNonUniqueOrDotless(const std::string& hostname) { | 446 bool IsHostnameNonUniqueOrDotless(const std::string& hostname) { |
| 417 return net::IsHostnameNonUnique(hostname) || | 447 return net::IsHostnameNonUnique(hostname) || |
| 418 hostname.find('.') == std::string::npos; | 448 hostname.find('.') == std::string::npos; |
| 419 } | 449 } |
| 420 | 450 |
| 421 } // namespace ssl_errors | 451 } // namespace ssl_errors |
| OLD | NEW |