OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 <vector> | 5 #include <vector> |
6 | 6 |
7 #include "chrome/browser/ssl/ssl_error_classification.h" | 7 #include "chrome/browser/ssl/ssl_error_classification.h" |
8 | 8 |
9 #include "base/build_time.h" | 9 #include "base/build_time.h" |
10 #include "base/metrics/field_trial.h" | 10 #include "base/metrics/field_trial.h" |
11 #include "base/metrics/histogram.h" | 11 #include "base/metrics/histogram.h" |
12 #include "base/strings/string_split.h" | 12 #include "base/strings/string_split.h" |
13 #include "base/strings/utf_string_conversions.h" | 13 #include "base/strings/utf_string_conversions.h" |
14 #include "base/time/time.h" | 14 #include "base/time/time.h" |
| 15 #include "chrome/browser/browser_process.h" |
| 16 #include "chrome/browser/chrome_notification_types.h" |
| 17 #include "chrome/browser/profiles/profile.h" |
15 #include "chrome/browser/ssl/ssl_error_info.h" | 18 #include "chrome/browser/ssl/ssl_error_info.h" |
| 19 #include "content/public/browser/notification_service.h" |
| 20 #include "content/public/browser/web_contents.h" |
16 #include "net/base/net_util.h" | 21 #include "net/base/net_util.h" |
17 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" | 22 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" |
18 #include "net/cert/x509_cert_types.h" | 23 #include "net/cert/x509_cert_types.h" |
19 #include "net/cert/x509_certificate.h" | 24 #include "net/cert/x509_certificate.h" |
20 #include "url/gurl.h" | 25 #include "url/gurl.h" |
21 | 26 |
22 using base::Time; | 27 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) |
23 using base::TimeTicks; | 28 #include "chrome/browser/captive_portal/captive_portal_service.h" |
24 using base::TimeDelta; | 29 #include "chrome/browser/captive_portal/captive_portal_service_factory.h" |
| 30 #endif |
25 | 31 |
26 #if defined(OS_WIN) | 32 #if defined(OS_WIN) |
27 #include "base/win/windows_version.h" | 33 #include "base/win/windows_version.h" |
28 #endif | 34 #endif |
29 | 35 |
| 36 using base::Time; |
| 37 using base::TimeTicks; |
| 38 using base::TimeDelta; |
| 39 |
30 namespace { | 40 namespace { |
31 | 41 |
32 // Events for UMA. Do not reorder or change! | 42 // Events for UMA. Do not reorder or change! |
33 enum SSLInterstitialCause { | 43 enum SSLInterstitialCause { |
34 CLOCK_PAST, | 44 CLOCK_PAST, |
35 CLOCK_FUTURE, | 45 CLOCK_FUTURE, |
36 WWW_SUBDOMAIN_MATCH, | 46 WWW_SUBDOMAIN_MATCH, |
37 SUBDOMAIN_MATCH, | 47 SUBDOMAIN_MATCH, |
38 SUBDOMAIN_INVERSE_MATCH, | 48 SUBDOMAIN_INVERSE_MATCH, |
39 SUBDOMAIN_OUTSIDE_WILDCARD, | 49 SUBDOMAIN_OUTSIDE_WILDCARD, |
40 HOST_NAME_NOT_KNOWN_TLD, | 50 HOST_NAME_NOT_KNOWN_TLD, |
| 51 LIKELY_MULTI_TENANT_HOSTING, |
41 UNUSED_INTERSTITIAL_CAUSE_ENTRY, | 52 UNUSED_INTERSTITIAL_CAUSE_ENTRY, |
42 }; | 53 }; |
43 | 54 |
| 55 // Events for UMA. Do not reorder or change! |
| 56 enum SSLInterstitialCauseCaptivePortal { |
| 57 CAPTIVE_PORTAL_DETECTION_ENABLED, |
| 58 CAPTIVE_PORTAL_DETECTION_ENABLED_OVERRIDABLE, |
| 59 CAPTIVE_PORTAL_PROBE_COMPLETED, |
| 60 CAPTIVE_PORTAL_PROBE_COMPLETED_OVERRIDABLE, |
| 61 CAPTIVE_PORTAL_NO_RESPONSE, |
| 62 CAPTIVE_PORTAL_NO_RESPONSE_OVERRIDABLE, |
| 63 CAPTIVE_PORTAL_DETECTED, |
| 64 CAPTIVE_PORTAL_DETECTED_OVERRIDABLE, |
| 65 UNUSED_CAPTIVE_PORTAL_EVENT, |
| 66 }; |
| 67 |
44 // Scores/weights which will be constant through all the SSL error types. | 68 // Scores/weights which will be constant through all the SSL error types. |
45 static const float kServerWeight = 0.5f; | 69 static const float kServerWeight = 0.5f; |
46 static const float kClientWeight = 0.5f; | 70 static const float kClientWeight = 0.5f; |
47 | 71 |
48 void RecordSSLInterstitialCause(bool overridable, SSLInterstitialCause event) { | 72 void RecordSSLInterstitialCause(bool overridable, SSLInterstitialCause event) { |
49 if (overridable) { | 73 if (overridable) { |
50 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.cause.overridable", event, | 74 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.cause.overridable", event, |
51 UNUSED_INTERSTITIAL_CAUSE_ENTRY); | 75 UNUSED_INTERSTITIAL_CAUSE_ENTRY); |
52 } else { | 76 } else { |
53 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.cause.nonoverridable", event, | 77 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.cause.nonoverridable", event, |
54 UNUSED_INTERSTITIAL_CAUSE_ENTRY); | 78 UNUSED_INTERSTITIAL_CAUSE_ENTRY); |
55 } | 79 } |
56 } | 80 } |
57 | 81 |
| 82 void RecordCaptivePortalEventStats(SSLInterstitialCauseCaptivePortal event) { |
| 83 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.captive_portal", |
| 84 event, |
| 85 UNUSED_CAPTIVE_PORTAL_EVENT); |
| 86 } |
| 87 |
| 88 int GetLevensteinDistance(const std::string& str1, |
| 89 const std::string& str2) { |
| 90 if (str1 == str2) |
| 91 return 0; |
| 92 if (str1.size() == 0) |
| 93 return str2.size(); |
| 94 if (str2.size() == 0) |
| 95 return str1.size(); |
| 96 std::vector<int> kFirstRow(str2.size() + 1, 0); |
| 97 std::vector<int> kSecondRow(str2.size() + 1, 0); |
| 98 |
| 99 for (size_t i = 0; i < kFirstRow.size(); ++i) |
| 100 kFirstRow[i] = i; |
| 101 for (size_t i = 0; i < str1.size(); ++i) { |
| 102 kSecondRow[0] = i + 1; |
| 103 for (size_t j = 0; j < str2.size(); ++j) { |
| 104 int cost = str1[i] == str2[j] ? 0 : 1; |
| 105 kSecondRow[j+1] = std::min(std::min( |
| 106 kSecondRow[j] + 1, kFirstRow[j + 1] + 1), kFirstRow[j] + cost); |
| 107 } |
| 108 for (size_t j = 0; j < kFirstRow.size(); j++) |
| 109 kFirstRow[j] = kSecondRow[j]; |
| 110 } |
| 111 return kSecondRow[str2.size()]; |
| 112 } |
| 113 |
58 } // namespace | 114 } // namespace |
59 | 115 |
60 SSLErrorClassification::SSLErrorClassification( | 116 SSLErrorClassification::SSLErrorClassification( |
| 117 content::WebContents* web_contents, |
61 const base::Time& current_time, | 118 const base::Time& current_time, |
62 const GURL& url, | 119 const GURL& url, |
| 120 int cert_error, |
63 const net::X509Certificate& cert) | 121 const net::X509Certificate& cert) |
64 : current_time_(current_time), | 122 : web_contents_(web_contents), |
| 123 current_time_(current_time), |
65 request_url_(url), | 124 request_url_(url), |
66 cert_(cert) { } | 125 cert_error_(cert_error), |
| 126 cert_(cert), |
| 127 captive_portal_detection_enabled_(false), |
| 128 captive_portal_probe_completed_(false), |
| 129 captive_portal_no_response_(false), |
| 130 captive_portal_detected_(false) { |
| 131 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) |
| 132 Profile* profile = Profile::FromBrowserContext( |
| 133 web_contents_->GetBrowserContext()); |
| 134 CaptivePortalService* captive_portal_service = |
| 135 CaptivePortalServiceFactory::GetForProfile(profile); |
| 136 captive_portal_detection_enabled_ = captive_portal_service->enabled(); |
| 137 captive_portal_service->DetectCaptivePortal(); |
| 138 registrar_.Add(this, |
| 139 chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT, |
| 140 content::Source<Profile>(profile)); |
| 141 #endif |
| 142 } |
67 | 143 |
68 SSLErrorClassification::~SSLErrorClassification() { } | 144 SSLErrorClassification::~SSLErrorClassification() { } |
69 | 145 |
70 float SSLErrorClassification::InvalidDateSeverityScore( | 146 void SSLErrorClassification::RecordCaptivePortalUMAStatistics( |
71 int cert_error) const { | 147 bool overridable) const { |
| 148 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) |
| 149 if (captive_portal_detection_enabled_) |
| 150 RecordCaptivePortalEventStats( |
| 151 overridable ? |
| 152 CAPTIVE_PORTAL_DETECTION_ENABLED_OVERRIDABLE : |
| 153 CAPTIVE_PORTAL_DETECTION_ENABLED); |
| 154 if (captive_portal_probe_completed_) |
| 155 RecordCaptivePortalEventStats( |
| 156 overridable ? |
| 157 CAPTIVE_PORTAL_PROBE_COMPLETED_OVERRIDABLE : |
| 158 CAPTIVE_PORTAL_PROBE_COMPLETED); |
| 159 // Log only one of portal detected and no response results. |
| 160 if (captive_portal_detected_) |
| 161 RecordCaptivePortalEventStats( |
| 162 overridable ? |
| 163 CAPTIVE_PORTAL_DETECTED_OVERRIDABLE : |
| 164 CAPTIVE_PORTAL_DETECTED); |
| 165 else if (captive_portal_no_response_) |
| 166 RecordCaptivePortalEventStats( |
| 167 overridable ? |
| 168 CAPTIVE_PORTAL_NO_RESPONSE_OVERRIDABLE : |
| 169 CAPTIVE_PORTAL_NO_RESPONSE); |
| 170 #endif |
| 171 } |
| 172 |
| 173 void SSLErrorClassification::InvalidDateSeverityScore() { |
72 SSLErrorInfo::ErrorType type = | 174 SSLErrorInfo::ErrorType type = |
73 SSLErrorInfo::NetErrorToErrorType(cert_error); | 175 SSLErrorInfo::NetErrorToErrorType(cert_error_); |
74 DCHECK(type == SSLErrorInfo::CERT_DATE_INVALID); | 176 DCHECK(type == SSLErrorInfo::CERT_DATE_INVALID); |
| 177 |
75 // Client-side characteristics. Check whether or not the system's clock is | 178 // Client-side characteristics. Check whether or not the system's clock is |
76 // wrong and whether or not the user has already encountered this error | 179 // wrong and whether or not the user has encountered this error before. |
77 // before. | |
78 float severity_date_score = 0.0f; | 180 float severity_date_score = 0.0f; |
79 | 181 |
80 static const float kCertificateExpiredWeight = 0.3f; | 182 static const float kCertificateExpiredWeight = 0.3f; |
81 static const float kNotYetValidWeight = 0.2f; | 183 static const float kNotYetValidWeight = 0.2f; |
82 | 184 |
83 static const float kSystemClockWeight = 0.75f; | 185 static const float kSystemClockWeight = 0.75f; |
84 static const float kSystemClockWrongWeight = 0.1f; | 186 static const float kSystemClockWrongWeight = 0.1f; |
85 static const float kSystemClockRightWeight = 1.0f; | 187 static const float kSystemClockRightWeight = 1.0f; |
86 | 188 |
87 if (IsUserClockInThePast(current_time_) || | 189 if (IsUserClockInThePast(current_time_) || |
88 IsUserClockInTheFuture(current_time_)) { | 190 IsUserClockInTheFuture(current_time_)) { |
89 severity_date_score += kClientWeight * kSystemClockWeight * | 191 severity_date_score += kClientWeight * kSystemClockWeight * |
90 kSystemClockWrongWeight; | 192 kSystemClockWrongWeight; |
91 } else { | 193 } else { |
92 severity_date_score += kClientWeight * kSystemClockWeight * | 194 severity_date_score += kClientWeight * kSystemClockWeight * |
93 kSystemClockRightWeight; | 195 kSystemClockRightWeight; |
94 } | 196 } |
95 // TODO(radhikabhar): (crbug.com/393262) Check website settings. | 197 // TODO(radhikabhar): (crbug.com/393262) Check website settings. |
96 | 198 |
97 // Server-side characteristics. Check whether the certificate has expired or | 199 // Server-side characteristics. Check whether the certificate has expired or |
98 // is not yet valid. If the certificate has expired then factor the time which | 200 // is not yet valid. If the certificate has expired then factor the time which |
99 // has passed since expiry. | 201 // has passed since expiry. |
100 if (cert_.HasExpired()) { | 202 if (cert_.HasExpired()) { |
101 severity_date_score += kServerWeight * kCertificateExpiredWeight * | 203 severity_date_score += kServerWeight * kCertificateExpiredWeight * |
102 CalculateScoreTimePassedSinceExpiry(); | 204 CalculateScoreTimePassedSinceExpiry(); |
103 } | 205 } |
104 if (current_time_ < cert_.valid_start()) | 206 if (current_time_ < cert_.valid_start()) |
105 severity_date_score += kServerWeight * kNotYetValidWeight; | 207 severity_date_score += kServerWeight * kNotYetValidWeight; |
106 return severity_date_score; | 208 // TODO(radhikabhar): Record the severity score in a histogram. This will be |
| 209 // in the next CL - just called the function in ssl_blocking_page.cc. |
107 } | 210 } |
108 | 211 |
109 float SSLErrorClassification::InvalidCommonNameSeverityScore( | 212 void SSLErrorClassification::InvalidCommonNameSeverityScore() { |
110 int cert_error) const { | |
111 SSLErrorInfo::ErrorType type = | 213 SSLErrorInfo::ErrorType type = |
112 SSLErrorInfo::NetErrorToErrorType(cert_error); | 214 SSLErrorInfo::NetErrorToErrorType(cert_error_); |
113 DCHECK(type == SSLErrorInfo::CERT_COMMON_NAME_INVALID); | 215 DCHECK(type == SSLErrorInfo::CERT_COMMON_NAME_INVALID); |
114 float severity_name_score = 0.0f; | 216 float severity_name_score = 0.0f; |
115 | 217 |
116 static const float kWWWDifferenceWeight = 0.3f; | 218 static const float kWWWDifferenceWeight = 0.3f; |
117 static const float kSubDomainWeight = 0.2f; | 219 static const float kNameUnderAnyNamesWeight = 0.2f; |
118 static const float kSubDomainInverseWeight = 1.0f; | 220 static const float kAnyNamesUnderNamesWeight = 1.0f; |
| 221 static const float kLikelyMultiTenantHostingWeight = 0.1f; |
119 | 222 |
120 std::string host_name = request_url_.host(); | 223 std::string host_name = request_url_.host(); |
121 if (IsHostNameKnownTLD(host_name)) { | 224 if (IsHostNameKnownTLD(host_name)) { |
122 Tokens host_name_tokens = Tokenize(host_name); | 225 Tokens host_name_tokens = Tokenize(host_name); |
123 if (IsWWWSubDomainMatch()) | 226 if (IsWWWSubDomainMatch()) |
124 severity_name_score += kServerWeight * kWWWDifferenceWeight; | 227 severity_name_score += kServerWeight * kWWWDifferenceWeight; |
125 if (IsSubDomainOutsideWildcard(host_name_tokens)) | 228 if (IsSubDomainOutsideWildcard(host_name_tokens)) |
126 severity_name_score += kServerWeight * kWWWDifferenceWeight; | 229 severity_name_score += kServerWeight * kWWWDifferenceWeight; |
127 | 230 |
128 std::vector<std::string> dns_names; | 231 std::vector<std::string> dns_names; |
129 cert_.GetDNSNames(&dns_names); | 232 cert_.GetDNSNames(&dns_names); |
130 std::vector<Tokens> dns_name_tokens = GetTokenizedDNSNames(dns_names); | 233 std::vector<Tokens> dns_name_tokens = GetTokenizedDNSNames(dns_names); |
131 if (NameUnderAnyNames(host_name_tokens, dns_name_tokens)) | 234 if (NameUnderAnyNames(host_name_tokens, dns_name_tokens)) |
132 severity_name_score += kServerWeight * kSubDomainWeight; | 235 severity_name_score += kServerWeight * kNameUnderAnyNamesWeight; |
133 // Inverse case is more likely to be a MITM attack. | 236 // Inverse case is more likely to be a MITM attack. |
134 if (AnyNamesUnderName(dns_name_tokens, host_name_tokens)) | 237 if (AnyNamesUnderName(dns_name_tokens, host_name_tokens)) |
135 severity_name_score += kServerWeight * kSubDomainInverseWeight; | 238 severity_name_score += kServerWeight * kAnyNamesUnderNamesWeight; |
| 239 if (IsCertLikelyFromMultiTenantHosting()) |
| 240 severity_name_score += kServerWeight * kLikelyMultiTenantHostingWeight; |
136 } | 241 } |
137 return severity_name_score; | 242 |
| 243 static const float kEnvironmentWeight = 0.25f; |
| 244 |
| 245 severity_name_score += kClientWeight * kEnvironmentWeight * |
| 246 CalculateScoreEnvironments(); |
| 247 // TODO(radhikabhar): Record the severity score in a histogram. Same as above |
| 248 // - this will be in the next CL. So just called the function in the |
| 249 // ssl_blocking_page.cc. |
138 } | 250 } |
139 | 251 |
140 void SSLErrorClassification::RecordUMAStatistics(bool overridable, | 252 void SSLErrorClassification::RecordUMAStatistics( |
141 int cert_error) { | 253 bool overridable) const { |
142 SSLErrorInfo::ErrorType type = | 254 SSLErrorInfo::ErrorType type = |
143 SSLErrorInfo::NetErrorToErrorType(cert_error); | 255 SSLErrorInfo::NetErrorToErrorType(cert_error_); |
144 switch (type) { | 256 switch (type) { |
145 case SSLErrorInfo::CERT_DATE_INVALID: { | 257 case SSLErrorInfo::CERT_DATE_INVALID: { |
146 if (IsUserClockInThePast(base::Time::NowFromSystemTime())) | 258 if (IsUserClockInThePast(base::Time::NowFromSystemTime())) |
147 RecordSSLInterstitialCause(overridable, CLOCK_PAST); | 259 RecordSSLInterstitialCause(overridable, CLOCK_PAST); |
148 if (IsUserClockInTheFuture(base::Time::NowFromSystemTime())) | 260 if (IsUserClockInTheFuture(base::Time::NowFromSystemTime())) |
149 RecordSSLInterstitialCause(overridable, CLOCK_FUTURE); | 261 RecordSSLInterstitialCause(overridable, CLOCK_FUTURE); |
150 break; | 262 break; |
151 } | 263 } |
152 case SSLErrorInfo::CERT_COMMON_NAME_INVALID: { | 264 case SSLErrorInfo::CERT_COMMON_NAME_INVALID: { |
153 std::string host_name = request_url_.host(); | 265 std::string host_name = request_url_.host(); |
154 if (IsHostNameKnownTLD(host_name)) { | 266 if (IsHostNameKnownTLD(host_name)) { |
155 Tokens host_name_tokens = Tokenize(host_name); | 267 Tokens host_name_tokens = Tokenize(host_name); |
156 if (IsWWWSubDomainMatch()) | 268 if (IsWWWSubDomainMatch()) |
157 RecordSSLInterstitialCause(overridable, WWW_SUBDOMAIN_MATCH); | 269 RecordSSLInterstitialCause(overridable, WWW_SUBDOMAIN_MATCH); |
158 if (IsSubDomainOutsideWildcard(host_name_tokens)) | 270 if (IsSubDomainOutsideWildcard(host_name_tokens)) |
159 RecordSSLInterstitialCause(overridable, SUBDOMAIN_OUTSIDE_WILDCARD); | 271 RecordSSLInterstitialCause(overridable, SUBDOMAIN_OUTSIDE_WILDCARD); |
160 std::vector<std::string> dns_names; | 272 std::vector<std::string> dns_names; |
161 cert_.GetDNSNames(&dns_names); | 273 cert_.GetDNSNames(&dns_names); |
162 std::vector<Tokens> dns_name_tokens = GetTokenizedDNSNames(dns_names); | 274 std::vector<Tokens> dns_name_tokens = GetTokenizedDNSNames(dns_names); |
163 if (NameUnderAnyNames(host_name_tokens, dns_name_tokens)) | 275 if (NameUnderAnyNames(host_name_tokens, dns_name_tokens)) |
164 RecordSSLInterstitialCause(overridable, SUBDOMAIN_MATCH); | 276 RecordSSLInterstitialCause(overridable, SUBDOMAIN_MATCH); |
165 if (AnyNamesUnderName(dns_name_tokens, host_name_tokens)) | 277 if (AnyNamesUnderName(dns_name_tokens, host_name_tokens)) |
166 RecordSSLInterstitialCause(overridable, SUBDOMAIN_INVERSE_MATCH); | 278 RecordSSLInterstitialCause(overridable, SUBDOMAIN_INVERSE_MATCH); |
| 279 if (IsCertLikelyFromMultiTenantHosting()) |
| 280 RecordSSLInterstitialCause(overridable, LIKELY_MULTI_TENANT_HOSTING); |
167 } else { | 281 } else { |
168 RecordSSLInterstitialCause(overridable, HOST_NAME_NOT_KNOWN_TLD); | 282 RecordSSLInterstitialCause(overridable, HOST_NAME_NOT_KNOWN_TLD); |
169 } | 283 } |
170 break; | 284 break; |
171 } | 285 } |
172 default: { | 286 default: { |
173 break; | 287 break; |
174 } | 288 } |
175 } | 289 } |
176 } | 290 } |
(...skipping 12 matching lines...) Expand all Loading... |
189 static const float kMediumThresholdWeight = 0.3f; | 303 static const float kMediumThresholdWeight = 0.3f; |
190 static const float kLowThresholdWeight = 0.2f; | 304 static const float kLowThresholdWeight = 0.2f; |
191 if (time_passed >= kHighThreshold) | 305 if (time_passed >= kHighThreshold) |
192 return kHighThresholdWeight; | 306 return kHighThresholdWeight; |
193 else if (time_passed >= kLowThreshold) | 307 else if (time_passed >= kLowThreshold) |
194 return kMediumThresholdWeight; | 308 return kMediumThresholdWeight; |
195 else | 309 else |
196 return kLowThresholdWeight; | 310 return kLowThresholdWeight; |
197 } | 311 } |
198 | 312 |
| 313 float SSLErrorClassification::CalculateScoreEnvironments() const { |
| 314 static const float kWifiWeight = 0.7f; |
| 315 static const float kCellularWeight = 0.7f; |
| 316 static const float kHotspotWeight = 0.2f; |
| 317 static const float kEthernetWeight = 0.7f; |
| 318 static const float kOtherWeight = 0.7f; |
| 319 net::NetworkChangeNotifier::ConnectionType type = |
| 320 net::NetworkChangeNotifier::GetConnectionType(); |
| 321 if (type == net::NetworkChangeNotifier::CONNECTION_WIFI) |
| 322 return kWifiWeight; |
| 323 if (type == net::NetworkChangeNotifier::CONNECTION_2G || |
| 324 type == net::NetworkChangeNotifier::CONNECTION_3G || |
| 325 type == net::NetworkChangeNotifier::CONNECTION_4G ) { |
| 326 return kCellularWeight; |
| 327 } |
| 328 if (type == net::NetworkChangeNotifier::CONNECTION_ETHERNET) |
| 329 return kEthernetWeight; |
| 330 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) |
| 331 // Assume if captive portals are detected then the user is connected using a |
| 332 // hot spot. |
| 333 if (captive_portal_probe_completed_ && captive_portal_detected_) |
| 334 return kHotspotWeight; |
| 335 #endif |
| 336 return kOtherWeight; |
| 337 } |
| 338 |
199 bool SSLErrorClassification::IsUserClockInThePast(const base::Time& time_now) { | 339 bool SSLErrorClassification::IsUserClockInThePast(const base::Time& time_now) { |
200 base::Time build_time = base::GetBuildTime(); | 340 base::Time build_time = base::GetBuildTime(); |
201 if (time_now < build_time - base::TimeDelta::FromDays(2)) | 341 if (time_now < build_time - base::TimeDelta::FromDays(2)) |
202 return true; | 342 return true; |
203 return false; | 343 return false; |
204 } | 344 } |
205 | 345 |
206 bool SSLErrorClassification::IsUserClockInTheFuture( | 346 bool SSLErrorClassification::IsUserClockInTheFuture( |
207 const base::Time& time_now) { | 347 const base::Time& time_now) { |
208 base::Time build_time = base::GetBuildTime(); | 348 base::Time build_time = base::GetBuildTime(); |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
359 | 499 |
360 // Move past the "*.". | 500 // Move past the "*.". |
361 std::string extracted_dns_name = name.substr(2); | 501 std::string extracted_dns_name = name.substr(2); |
362 if (FindSubDomainDifference( | 502 if (FindSubDomainDifference( |
363 host_name_tokens, Tokenize(extracted_dns_name)) == 2) { | 503 host_name_tokens, Tokenize(extracted_dns_name)) == 2) { |
364 return true; | 504 return true; |
365 } | 505 } |
366 } | 506 } |
367 return result; | 507 return result; |
368 } | 508 } |
| 509 |
| 510 bool SSLErrorClassification::IsCertLikelyFromMultiTenantHosting() const { |
| 511 std::string host_name = request_url_.host(); |
| 512 std::vector<std::string> dns_names; |
| 513 std::vector<std::string> dns_names_domain; |
| 514 cert_.GetDNSNames(&dns_names); |
| 515 size_t dns_names_size = dns_names.size(); |
| 516 |
| 517 // If there is only 1 DNS name then it is definitely not a shared certificate. |
| 518 if (dns_names_size == 0 || dns_names_size == 1) |
| 519 return false; |
| 520 |
| 521 // Check to see if all the domains in the SAN field in the SSL certificate are |
| 522 // the same or not. |
| 523 for (size_t i = 0; i < dns_names_size; ++i) { |
| 524 dns_names_domain.push_back( |
| 525 net::registry_controlled_domains:: |
| 526 GetDomainAndRegistry( |
| 527 dns_names[i], |
| 528 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)); |
| 529 } |
| 530 for (size_t i = 1; i < dns_names_domain.size(); ++i) { |
| 531 if (dns_names_domain[i] != dns_names_domain[0]) |
| 532 return false; |
| 533 } |
| 534 |
| 535 // If the number of DNS names is more than 5 then assume that it is a shared |
| 536 // certificate. |
| 537 static const int kDistinctNameThreshold = 5; |
| 538 if (dns_names_size > kDistinctNameThreshold) |
| 539 return true; |
| 540 |
| 541 // Heuristic - The edit distance between all the strings should be at least 5 |
| 542 // for it to be counted as a shared SSLCertificate. If even one pair of |
| 543 // strings edit distance is below 5 then the certificate is no longer |
| 544 // considered as a shared certificate. Include the host name in the URL also |
| 545 // while comparing. |
| 546 dns_names.push_back(host_name); |
| 547 static const int kMinimumEditDsitance = 5; |
| 548 for (size_t i = 0; i < dns_names_size; ++i) { |
| 549 for (size_t j = i + 1; j < dns_names_size; ++j) { |
| 550 int edit_distance = GetLevensteinDistance(dns_names[i], dns_names[j]); |
| 551 if (edit_distance < kMinimumEditDsitance) |
| 552 return false; |
| 553 } |
| 554 } |
| 555 return true; |
| 556 } |
| 557 |
| 558 |
| 559 void SSLErrorClassification::Observe( |
| 560 int type, |
| 561 const content::NotificationSource& source, |
| 562 const content::NotificationDetails& details) { |
| 563 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) |
| 564 // When detection is disabled, captive portal service always sends |
| 565 // RESULT_INTERNET_CONNECTED. Ignore any probe results in that case. |
| 566 if (!captive_portal_detection_enabled_) |
| 567 return; |
| 568 if (type == chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT) { |
| 569 captive_portal_probe_completed_ = true; |
| 570 CaptivePortalService::Results* results = |
| 571 content::Details<CaptivePortalService::Results>( |
| 572 details).ptr(); |
| 573 // If a captive portal was detected at any point when the interstitial was |
| 574 // displayed, assume that the interstitial was caused by a captive portal. |
| 575 // Example scenario: |
| 576 // 1- Interstitial displayed and captive portal detected, setting the flag. |
| 577 // 2- Captive portal detection automatically opens portal login page. |
| 578 // 3- User logs in on the portal login page. |
| 579 // A notification will be received here for RESULT_INTERNET_CONNECTED. Make |
| 580 // sure we don't clear the captive protal flag, since the interstitial was |
| 581 // potentially caused by the captive portal. |
| 582 captive_portal_detected_ = captive_portal_detected_ || |
| 583 (results->result == captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL); |
| 584 // Also keep track of non-HTTP portals and error cases. |
| 585 captive_portal_no_response_ = captive_portal_no_response_ || |
| 586 (results->result == captive_portal::RESULT_NO_RESPONSE); |
| 587 } |
| 588 #endif |
| 589 } |
OLD | NEW |