Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(96)

Side by Side Diff: components/ssl_errors/error_classification.cc

Issue 1355413003: Move error classification into the ssl_errors component (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 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"
6
5 #include <vector> 7 #include <vector>
6 8
7 #include "chrome/browser/ssl/ssl_error_classification.h"
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"
18 #include "components/ssl_errors/error_info.h" 15 #include "components/ssl_errors/error_info.h"
19 #include "content/public/browser/notification_service.h"
20 #include "content/public/browser/web_contents.h"
21 #include "net/base/net_util.h" 16 #include "net/base/net_util.h"
22 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" 17 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
23 #include "net/cert/x509_cert_types.h" 18 #include "net/cert/x509_cert_types.h"
24 #include "net/cert/x509_certificate.h" 19 #include "net/cert/x509_certificate.h"
25 #include "url/gurl.h" 20 #include "url/gurl.h"
26 21
27 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
28 #include "chrome/browser/captive_portal/captive_portal_service.h"
29 #include "chrome/browser/captive_portal/captive_portal_service_factory.h"
30 #endif
31
32 #if defined(OS_WIN) 22 #if defined(OS_WIN)
33 #include "base/win/win_util.h" 23 #include "base/win/win_util.h"
34 #include "base/win/windows_version.h" 24 #include "base/win/windows_version.h"
35 #endif 25 #endif
36 26
37 using base::Time; 27 using base::Time;
38 using base::TimeTicks; 28 using base::TimeTicks;
39 using base::TimeDelta; 29 using base::TimeDelta;
40 30
31 namespace ssl_errors {
32
41 namespace { 33 namespace {
42 34
43 // Events for UMA. Do not reorder or change! 35 // Events for UMA. Do not reorder or change!
44 enum SSLInterstitialCause { 36 enum SSLInterstitialCause {
45 CLOCK_PAST, 37 CLOCK_PAST,
46 CLOCK_FUTURE, 38 CLOCK_FUTURE,
47 WWW_SUBDOMAIN_MATCH, 39 WWW_SUBDOMAIN_MATCH,
48 SUBDOMAIN_MATCH, 40 SUBDOMAIN_MATCH,
49 SUBDOMAIN_INVERSE_MATCH, 41 SUBDOMAIN_INVERSE_MATCH,
50 SUBDOMAIN_OUTSIDE_WILDCARD, 42 SUBDOMAIN_OUTSIDE_WILDCARD,
51 HOST_NAME_NOT_KNOWN_TLD, 43 HOST_NAME_NOT_KNOWN_TLD,
52 LIKELY_MULTI_TENANT_HOSTING, 44 LIKELY_MULTI_TENANT_HOSTING,
53 LOCALHOST, 45 LOCALHOST,
54 PRIVATE_URL, 46 PRIVATE_URL,
55 AUTHORITY_ERROR_CAPTIVE_PORTAL, 47 AUTHORITY_ERROR_CAPTIVE_PORTAL, // Deprecated.
56 SELF_SIGNED, 48 SELF_SIGNED,
57 EXPIRED_RECENTLY, 49 EXPIRED_RECENTLY,
58 LIKELY_SAME_DOMAIN, 50 LIKELY_SAME_DOMAIN,
59 UNUSED_INTERSTITIAL_CAUSE_ENTRY, 51 UNUSED_INTERSTITIAL_CAUSE_ENTRY,
60 }; 52 };
61 53
62 // Events for UMA. Do not reorder or change!
63 enum SSLInterstitialCauseCaptivePortal {
64 CAPTIVE_PORTAL_ALL,
65 CAPTIVE_PORTAL_DETECTION_ENABLED,
66 CAPTIVE_PORTAL_DETECTION_ENABLED_OVERRIDABLE,
67 CAPTIVE_PORTAL_PROBE_COMPLETED,
68 CAPTIVE_PORTAL_PROBE_COMPLETED_OVERRIDABLE,
69 CAPTIVE_PORTAL_NO_RESPONSE,
70 CAPTIVE_PORTAL_NO_RESPONSE_OVERRIDABLE,
71 CAPTIVE_PORTAL_DETECTED,
72 CAPTIVE_PORTAL_DETECTED_OVERRIDABLE,
73 UNUSED_CAPTIVE_PORTAL_EVENT,
74 };
75
76 void RecordSSLInterstitialCause(bool overridable, SSLInterstitialCause event) { 54 void RecordSSLInterstitialCause(bool overridable, SSLInterstitialCause event) {
77 if (overridable) { 55 if (overridable) {
78 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.cause.overridable", event, 56 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.cause.overridable", event,
79 UNUSED_INTERSTITIAL_CAUSE_ENTRY); 57 UNUSED_INTERSTITIAL_CAUSE_ENTRY);
80 } else { 58 } else {
81 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.cause.nonoverridable", event, 59 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.cause.nonoverridable", event,
82 UNUSED_INTERSTITIAL_CAUSE_ENTRY); 60 UNUSED_INTERSTITIAL_CAUSE_ENTRY);
83 } 61 }
84 } 62 }
85 63
86 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) 64 int GetLevensteinDistance(const std::string& str1, const std::string& str2) {
87 void RecordCaptivePortalEventStats(SSLInterstitialCauseCaptivePortal event) {
88 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.captive_portal",
89 event,
90 UNUSED_CAPTIVE_PORTAL_EVENT);
91 }
92 #endif
93
94 int GetLevensteinDistance(const std::string& str1,
95 const std::string& str2) {
96 if (str1 == str2) 65 if (str1 == str2)
97 return 0; 66 return 0;
98 if (str1.size() == 0) 67 if (str1.size() == 0)
99 return str2.size(); 68 return str2.size();
100 if (str2.size() == 0) 69 if (str2.size() == 0)
101 return str1.size(); 70 return str1.size();
102 std::vector<int> kFirstRow(str2.size() + 1, 0); 71 std::vector<int> kFirstRow(str2.size() + 1, 0);
103 std::vector<int> kSecondRow(str2.size() + 1, 0); 72 std::vector<int> kSecondRow(str2.size() + 1, 0);
104 73
105 for (size_t i = 0; i < kFirstRow.size(); ++i) 74 for (size_t i = 0; i < kFirstRow.size(); ++i)
106 kFirstRow[i] = i; 75 kFirstRow[i] = i;
107 for (size_t i = 0; i < str1.size(); ++i) { 76 for (size_t i = 0; i < str1.size(); ++i) {
108 kSecondRow[0] = i + 1; 77 kSecondRow[0] = i + 1;
109 for (size_t j = 0; j < str2.size(); ++j) { 78 for (size_t j = 0; j < str2.size(); ++j) {
110 int cost = str1[i] == str2[j] ? 0 : 1; 79 int cost = str1[i] == str2[j] ? 0 : 1;
111 kSecondRow[j+1] = std::min(std::min( 80 kSecondRow[j + 1] =
112 kSecondRow[j] + 1, kFirstRow[j + 1] + 1), kFirstRow[j] + cost); 81 std::min(std::min(kSecondRow[j] + 1, kFirstRow[j + 1] + 1),
82 kFirstRow[j] + cost);
113 } 83 }
114 for (size_t j = 0; j < kFirstRow.size(); j++) 84 for (size_t j = 0; j < kFirstRow.size(); j++)
115 kFirstRow[j] = kSecondRow[j]; 85 kFirstRow[j] = kSecondRow[j];
116 } 86 }
117 return kSecondRow[str2.size()]; 87 return kSecondRow[str2.size()];
118 } 88 }
119 89
120 // The time to use when doing build time operations in browser tests. 90 // The time to use when doing build time operations in browser tests.
121 base::Time g_testing_build_time; 91 base::Time g_testing_build_time;
122 92
123 } // namespace 93 } // namespace
124 94
125 SSLErrorClassification::SSLErrorClassification( 95 ErrorClassification::ErrorClassification(const base::Time& current_time,
126 content::WebContents* web_contents, 96 const GURL& url,
127 const base::Time& current_time, 97 int cert_error,
128 const GURL& url, 98 const net::X509Certificate& cert)
129 int cert_error, 99 : current_time_(current_time),
130 const net::X509Certificate& cert) 100 request_url_(url),
131 : web_contents_(web_contents), 101 cert_error_(cert_error),
132 current_time_(current_time), 102 cert_(cert) {}
133 request_url_(url),
134 cert_error_(cert_error),
135 cert_(cert),
136 captive_portal_detection_enabled_(false),
137 captive_portal_probe_completed_(false),
138 captive_portal_no_response_(false),
139 captive_portal_detected_(false) {
140 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
141 Profile* profile = Profile::FromBrowserContext(
142 web_contents_->GetBrowserContext());
143 captive_portal_detection_enabled_ =
144 CaptivePortalServiceFactory::GetForProfile(profile)->enabled();
145 registrar_.Add(this,
146 chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT,
147 content::Source<Profile>(profile));
148 #endif
149 }
150 103
151 SSLErrorClassification::~SSLErrorClassification() { } 104 ErrorClassification::~ErrorClassification() {}
152 105
153 void SSLErrorClassification::RecordCaptivePortalUMAStatistics( 106 void ErrorClassification::RecordUMAStatistics(bool overridable) const {
154 bool overridable) const { 107 ErrorInfo::ErrorType type = ErrorInfo::NetErrorToErrorType(cert_error_);
155 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
156 RecordCaptivePortalEventStats(CAPTIVE_PORTAL_ALL);
157 if (captive_portal_detection_enabled_)
158 RecordCaptivePortalEventStats(
159 overridable ?
160 CAPTIVE_PORTAL_DETECTION_ENABLED_OVERRIDABLE :
161 CAPTIVE_PORTAL_DETECTION_ENABLED);
162 if (captive_portal_probe_completed_)
163 RecordCaptivePortalEventStats(
164 overridable ?
165 CAPTIVE_PORTAL_PROBE_COMPLETED_OVERRIDABLE :
166 CAPTIVE_PORTAL_PROBE_COMPLETED);
167 // Log only one of portal detected and no response results.
168 if (captive_portal_detected_)
169 RecordCaptivePortalEventStats(
170 overridable ?
171 CAPTIVE_PORTAL_DETECTED_OVERRIDABLE :
172 CAPTIVE_PORTAL_DETECTED);
173 else if (captive_portal_no_response_)
174 RecordCaptivePortalEventStats(
175 overridable ?
176 CAPTIVE_PORTAL_NO_RESPONSE_OVERRIDABLE :
177 CAPTIVE_PORTAL_NO_RESPONSE);
178 #endif
179 }
180
181 void SSLErrorClassification::RecordUMAStatistics(
182 bool overridable) const {
183 ssl_errors::ErrorInfo::ErrorType type =
184 ssl_errors::ErrorInfo::NetErrorToErrorType(cert_error_);
185 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl_error_type", type, 108 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl_error_type", type,
186 ssl_errors::ErrorInfo::END_OF_ENUM); 109 ErrorInfo::END_OF_ENUM);
187 switch (type) { 110 switch (type) {
188 case ssl_errors::ErrorInfo::CERT_DATE_INVALID: { 111 case ErrorInfo::CERT_DATE_INVALID: {
189 if (IsUserClockInThePast(base::Time::NowFromSystemTime())) { 112 if (IsUserClockInThePast(base::Time::NowFromSystemTime())) {
190 RecordSSLInterstitialCause(overridable, CLOCK_PAST); 113 RecordSSLInterstitialCause(overridable, CLOCK_PAST);
191 } else if (IsUserClockInTheFuture(base::Time::NowFromSystemTime())) { 114 } else if (IsUserClockInTheFuture(base::Time::NowFromSystemTime())) {
192 RecordSSLInterstitialCause(overridable, CLOCK_FUTURE); 115 RecordSSLInterstitialCause(overridable, CLOCK_FUTURE);
193 } else if (cert_.HasExpired() && TimePassedSinceExpiry().InDays() < 28) { 116 } else if (cert_.HasExpired() && TimePassedSinceExpiry().InDays() < 28) {
194 RecordSSLInterstitialCause(overridable, EXPIRED_RECENTLY); 117 RecordSSLInterstitialCause(overridable, EXPIRED_RECENTLY);
195 } 118 }
196 break; 119 break;
197 } 120 }
198 case ssl_errors::ErrorInfo::CERT_COMMON_NAME_INVALID: { 121 case ErrorInfo::CERT_COMMON_NAME_INVALID: {
199 std::string host_name = request_url_.host(); 122 std::string host_name = request_url_.host();
200 if (IsHostNameKnownTLD(host_name)) { 123 if (IsHostNameKnownTLD(host_name)) {
201 Tokens host_name_tokens = Tokenize(host_name); 124 Tokens host_name_tokens = Tokenize(host_name);
202 if (IsWWWSubDomainMatch()) 125 if (IsWWWSubDomainMatch())
203 RecordSSLInterstitialCause(overridable, WWW_SUBDOMAIN_MATCH); 126 RecordSSLInterstitialCause(overridable, WWW_SUBDOMAIN_MATCH);
204 if (IsSubDomainOutsideWildcard(host_name_tokens)) 127 if (IsSubDomainOutsideWildcard(host_name_tokens))
205 RecordSSLInterstitialCause(overridable, SUBDOMAIN_OUTSIDE_WILDCARD); 128 RecordSSLInterstitialCause(overridable, SUBDOMAIN_OUTSIDE_WILDCARD);
206 std::vector<std::string> dns_names; 129 std::vector<std::string> dns_names;
207 cert_.GetDNSNames(&dns_names); 130 cert_.GetDNSNames(&dns_names);
208 std::vector<Tokens> dns_name_tokens = GetTokenizedDNSNames(dns_names); 131 std::vector<Tokens> dns_name_tokens = GetTokenizedDNSNames(dns_names);
209 if (NameUnderAnyNames(host_name_tokens, dns_name_tokens)) 132 if (NameUnderAnyNames(host_name_tokens, dns_name_tokens))
210 RecordSSLInterstitialCause(overridable, SUBDOMAIN_MATCH); 133 RecordSSLInterstitialCause(overridable, SUBDOMAIN_MATCH);
211 if (AnyNamesUnderName(dns_name_tokens, host_name_tokens)) 134 if (AnyNamesUnderName(dns_name_tokens, host_name_tokens))
212 RecordSSLInterstitialCause(overridable, SUBDOMAIN_INVERSE_MATCH); 135 RecordSSLInterstitialCause(overridable, SUBDOMAIN_INVERSE_MATCH);
213 if (IsCertLikelyFromMultiTenantHosting()) 136 if (IsCertLikelyFromMultiTenantHosting())
214 RecordSSLInterstitialCause(overridable, LIKELY_MULTI_TENANT_HOSTING); 137 RecordSSLInterstitialCause(overridable, LIKELY_MULTI_TENANT_HOSTING);
215 if (IsCertLikelyFromSameDomain()) 138 if (IsCertLikelyFromSameDomain())
216 RecordSSLInterstitialCause(overridable, LIKELY_SAME_DOMAIN); 139 RecordSSLInterstitialCause(overridable, LIKELY_SAME_DOMAIN);
217 } else { 140 } else {
218 RecordSSLInterstitialCause(overridable, HOST_NAME_NOT_KNOWN_TLD); 141 RecordSSLInterstitialCause(overridable, HOST_NAME_NOT_KNOWN_TLD);
219 } 142 }
220 break; 143 break;
221 } 144 }
222 case ssl_errors::ErrorInfo::CERT_AUTHORITY_INVALID: { 145 case ErrorInfo::CERT_AUTHORITY_INVALID: {
223 const std::string& hostname = request_url_.HostNoBrackets(); 146 const std::string& hostname = request_url_.HostNoBrackets();
224 if (net::IsLocalhost(hostname)) 147 if (net::IsLocalhost(hostname))
225 RecordSSLInterstitialCause(overridable, LOCALHOST); 148 RecordSSLInterstitialCause(overridable, LOCALHOST);
226 if (IsHostnameNonUniqueOrDotless(hostname)) 149 if (IsHostnameNonUniqueOrDotless(hostname))
227 RecordSSLInterstitialCause(overridable, PRIVATE_URL); 150 RecordSSLInterstitialCause(overridable, PRIVATE_URL);
228 if (captive_portal_probe_completed_ && captive_portal_detected_)
229 RecordSSLInterstitialCause(overridable, AUTHORITY_ERROR_CAPTIVE_PORTAL);
230 if (net::X509Certificate::IsSelfSigned(cert_.os_cert_handle())) 151 if (net::X509Certificate::IsSelfSigned(cert_.os_cert_handle()))
231 RecordSSLInterstitialCause(overridable, SELF_SIGNED); 152 RecordSSLInterstitialCause(overridable, SELF_SIGNED);
232 break; 153 break;
233 } 154 }
234 default: 155 default:
235 break; 156 break;
236 } 157 }
237 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.connection_type", 158 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.connection_type",
238 net::NetworkChangeNotifier::GetConnectionType(), 159 net::NetworkChangeNotifier::GetConnectionType(),
239 net::NetworkChangeNotifier::CONNECTION_LAST); 160 net::NetworkChangeNotifier::CONNECTION_LAST);
240 } 161 }
241 162
242 base::TimeDelta SSLErrorClassification::TimePassedSinceExpiry() const { 163 base::TimeDelta ErrorClassification::TimePassedSinceExpiry() const {
243 base::TimeDelta delta = current_time_ - cert_.valid_expiry(); 164 base::TimeDelta delta = current_time_ - cert_.valid_expiry();
244 return delta; 165 return delta;
245 } 166 }
246 167
247 bool SSLErrorClassification::IsUserClockInThePast(const base::Time& time_now) { 168 bool ErrorClassification::IsUserClockInThePast(const base::Time& time_now) {
248 base::Time build_time; 169 base::Time build_time;
249 if (!g_testing_build_time.is_null()) { 170 if (!g_testing_build_time.is_null()) {
250 build_time = g_testing_build_time; 171 build_time = g_testing_build_time;
251 } else { 172 } else {
252 #if defined(DONT_EMBED_BUILD_METADATA) && !defined(OFFICIAL_BUILD) 173 #if defined(DONT_EMBED_BUILD_METADATA) && !defined(OFFICIAL_BUILD)
253 return false; 174 return false;
254 #else 175 #else
255 build_time = base::GetBuildTime(); 176 build_time = base::GetBuildTime();
256 #endif 177 #endif
257 } 178 }
258 179
259 if (time_now < build_time - base::TimeDelta::FromDays(2)) 180 if (time_now < build_time - base::TimeDelta::FromDays(2))
260 return true; 181 return true;
261 return false; 182 return false;
262 } 183 }
263 184
264 bool SSLErrorClassification::IsUserClockInTheFuture( 185 bool ErrorClassification::IsUserClockInTheFuture(const base::Time& time_now) {
265 const base::Time& time_now) {
266 base::Time build_time; 186 base::Time build_time;
267 if (!g_testing_build_time.is_null()) { 187 if (!g_testing_build_time.is_null()) {
268 build_time = g_testing_build_time; 188 build_time = g_testing_build_time;
269 } else { 189 } else {
270 #if defined(DONT_EMBED_BUILD_METADATA) && !defined(OFFICIAL_BUILD) 190 #if defined(DONT_EMBED_BUILD_METADATA) && !defined(OFFICIAL_BUILD)
271 return false; 191 return false;
272 #else 192 #else
273 build_time = base::GetBuildTime(); 193 build_time = base::GetBuildTime();
274 #endif 194 #endif
275 } 195 }
276 196
277 if (time_now > build_time + base::TimeDelta::FromDays(365)) 197 if (time_now > build_time + base::TimeDelta::FromDays(365))
278 return true; 198 return true;
279 return false; 199 return false;
280 } 200 }
281 201
282 // static 202 // static
283 void SSLErrorClassification::SetBuildTimeForTesting( 203 void ErrorClassification::SetBuildTimeForTesting(
284 const base::Time& testing_time) { 204 const base::Time& testing_time) {
285 g_testing_build_time = testing_time; 205 g_testing_build_time = testing_time;
286 } 206 }
287 207
288 bool SSLErrorClassification::MaybeWindowsLacksSHA256Support() { 208 bool ErrorClassification::MaybeWindowsLacksSHA256Support() {
289 #if defined(OS_WIN) 209 #if defined(OS_WIN)
290 return !base::win::MaybeHasSHA256Support(); 210 return !base::win::MaybeHasSHA256Support();
291 #else 211 #else
292 return false; 212 return false;
293 #endif 213 #endif
294 } 214 }
295 215
296 bool SSLErrorClassification::IsHostNameKnownTLD(const std::string& host_name) { 216 bool ErrorClassification::IsHostNameKnownTLD(const std::string& host_name) {
297 size_t tld_length = 217 size_t tld_length = net::registry_controlled_domains::GetRegistryLength(
298 net::registry_controlled_domains::GetRegistryLength( 218 host_name, net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES,
299 host_name, 219 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
300 net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES,
301 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
302 if (tld_length == 0 || tld_length == std::string::npos) 220 if (tld_length == 0 || tld_length == std::string::npos)
303 return false; 221 return false;
304 return true; 222 return true;
305 } 223 }
306 224
307 std::vector<SSLErrorClassification::Tokens> SSLErrorClassification:: 225 std::vector<ErrorClassification::Tokens>
308 GetTokenizedDNSNames(const std::vector<std::string>& dns_names) { 226 ErrorClassification::GetTokenizedDNSNames(
227 const std::vector<std::string>& dns_names) {
309 std::vector<std::vector<std::string>> dns_name_tokens; 228 std::vector<std::vector<std::string>> dns_name_tokens;
310 for (size_t i = 0; i < dns_names.size(); ++i) { 229 for (size_t i = 0; i < dns_names.size(); ++i) {
311 std::vector<std::string> dns_name_token_single; 230 std::vector<std::string> dns_name_token_single;
312 if (dns_names[i].empty() || dns_names[i].find('\0') != std::string::npos 231 if (dns_names[i].empty() || dns_names[i].find('\0') != std::string::npos ||
313 || !(IsHostNameKnownTLD(dns_names[i]))) { 232 !(IsHostNameKnownTLD(dns_names[i]))) {
314 dns_name_token_single.push_back(std::string()); 233 dns_name_token_single.push_back(std::string());
315 } else { 234 } else {
316 dns_name_token_single = Tokenize(dns_names[i]); 235 dns_name_token_single = Tokenize(dns_names[i]);
317 } 236 }
318 dns_name_tokens.push_back(dns_name_token_single); 237 dns_name_tokens.push_back(dns_name_token_single);
319 } 238 }
320 return dns_name_tokens; 239 return dns_name_tokens;
321 } 240 }
322 241
323 size_t SSLErrorClassification::FindSubDomainDifference( 242 size_t ErrorClassification::FindSubDomainDifference(
324 const Tokens& potential_subdomain, const Tokens& parent) const { 243 const Tokens& potential_subdomain,
244 const Tokens& parent) const {
325 // A check to ensure that the number of tokens in the tokenized_parent is 245 // A check to ensure that the number of tokens in the tokenized_parent is
326 // less than the tokenized_potential_subdomain. 246 // less than the tokenized_potential_subdomain.
327 if (parent.size() >= potential_subdomain.size()) 247 if (parent.size() >= potential_subdomain.size())
328 return 0; 248 return 0;
329 249
330 size_t tokens_match = 0; 250 size_t tokens_match = 0;
331 size_t diff_size = potential_subdomain.size() - parent.size(); 251 size_t diff_size = potential_subdomain.size() - parent.size();
332 for (size_t i = 0; i < parent.size(); ++i) { 252 for (size_t i = 0; i < parent.size(); ++i) {
333 if (parent[i] == potential_subdomain[i + diff_size]) 253 if (parent[i] == potential_subdomain[i + diff_size])
334 tokens_match++; 254 tokens_match++;
335 } 255 }
336 if (tokens_match == parent.size()) 256 if (tokens_match == parent.size())
337 return diff_size; 257 return diff_size;
338 return 0; 258 return 0;
339 } 259 }
340 260
341 SSLErrorClassification::Tokens SSLErrorClassification:: 261 ErrorClassification::Tokens ErrorClassification::Tokenize(
342 Tokenize(const std::string& name) { 262 const std::string& name) {
343 return base::SplitString( 263 return base::SplitString(name, ".", base::KEEP_WHITESPACE,
344 name, ".", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); 264 base::SPLIT_WANT_ALL);
345 } 265 }
346 266
347 // We accept the inverse case for www for historical reasons. 267 // We accept the inverse case for www for historical reasons.
348 bool SSLErrorClassification::GetWWWSubDomainMatch( 268 bool ErrorClassification::GetWWWSubDomainMatch(
349 const std::string& host_name, 269 const std::string& host_name,
350 const std::vector<std::string>& dns_names, 270 const std::vector<std::string>& dns_names,
351 std::string* www_match_host_name) { 271 std::string* www_match_host_name) {
352 if (IsHostNameKnownTLD(host_name)) { 272 if (IsHostNameKnownTLD(host_name)) {
353 // Need to account for all possible domains given in the SSL certificate. 273 // Need to account for all possible domains given in the SSL certificate.
354 for (size_t i = 0; i < dns_names.size(); ++i) { 274 for (size_t i = 0; i < dns_names.size(); ++i) {
355 if (dns_names[i].empty() || 275 if (dns_names[i].empty() ||
356 dns_names[i].find('\0') != std::string::npos || 276 dns_names[i].find('\0') != std::string::npos ||
357 dns_names[i].length() == host_name.length() || 277 dns_names[i].length() == host_name.length() ||
358 !IsHostNameKnownTLD(dns_names[i])) { 278 !IsHostNameKnownTLD(dns_names[i])) {
359 continue; 279 continue;
360 } else if (dns_names[i].length() > host_name.length()) { 280 } else if (dns_names[i].length() > host_name.length()) {
361 if (net::StripWWW(base::ASCIIToUTF16(dns_names[i])) == 281 if (net::StripWWW(base::ASCIIToUTF16(dns_names[i])) ==
362 base::ASCIIToUTF16(host_name)) { 282 base::ASCIIToUTF16(host_name)) {
363 *www_match_host_name = dns_names[i]; 283 *www_match_host_name = dns_names[i];
364 return true; 284 return true;
365 } 285 }
366 } else { 286 } else {
367 if (net::StripWWW(base::ASCIIToUTF16(host_name)) == 287 if (net::StripWWW(base::ASCIIToUTF16(host_name)) ==
368 base::ASCIIToUTF16(dns_names[i])) { 288 base::ASCIIToUTF16(dns_names[i])) {
369 *www_match_host_name = dns_names[i]; 289 *www_match_host_name = dns_names[i];
370 return true; 290 return true;
371 } 291 }
372 } 292 }
373 } 293 }
374 } 294 }
375 return false; 295 return false;
376 } 296 }
377 297
378 bool SSLErrorClassification::IsWWWSubDomainMatch() const { 298 bool ErrorClassification::IsWWWSubDomainMatch() const {
379 const std::string& host_name = request_url_.host(); 299 const std::string& host_name = request_url_.host();
380 std::vector<std::string> dns_names; 300 std::vector<std::string> dns_names;
381 cert_.GetDNSNames(&dns_names); 301 cert_.GetDNSNames(&dns_names);
382 std::string www_host; 302 std::string www_host;
383 return GetWWWSubDomainMatch(host_name, dns_names, &www_host); 303 return GetWWWSubDomainMatch(host_name, dns_names, &www_host);
384 } 304 }
385 305
386 bool SSLErrorClassification::NameUnderAnyNames( 306 bool ErrorClassification::NameUnderAnyNames(
387 const Tokens& child, 307 const Tokens& child,
388 const std::vector<Tokens>& potential_parents) const { 308 const std::vector<Tokens>& potential_parents) const {
389 bool result = false; 309 bool result = false;
390 // Need to account for all the possible domains given in the SSL certificate. 310 // Need to account for all the possible domains given in the SSL certificate.
391 for (size_t i = 0; i < potential_parents.size(); ++i) { 311 for (size_t i = 0; i < potential_parents.size(); ++i) {
392 if (potential_parents[i].empty() || 312 if (potential_parents[i].empty() ||
393 potential_parents[i].size() >= child.size()) { 313 potential_parents[i].size() >= child.size()) {
394 result = result || false; 314 result = result || false;
395 } else { 315 } else {
396 size_t domain_diff = FindSubDomainDifference(child, 316 size_t domain_diff = FindSubDomainDifference(child, potential_parents[i]);
397 potential_parents[i]); 317 if (domain_diff == 1 && child[0] != "www")
398 if (domain_diff == 1 && child[0] != "www")
399 result = result || true; 318 result = result || true;
400 } 319 }
401 } 320 }
402 return result; 321 return result;
403 } 322 }
404 323
405 bool SSLErrorClassification::AnyNamesUnderName( 324 bool ErrorClassification::AnyNamesUnderName(
406 const std::vector<Tokens>& potential_children, 325 const std::vector<Tokens>& potential_children,
407 const Tokens& parent) const { 326 const Tokens& parent) const {
408 bool result = false; 327 bool result = false;
409 // Need to account for all the possible domains given in the SSL certificate. 328 // Need to account for all the possible domains given in the SSL certificate.
410 for (size_t i = 0; i < potential_children.size(); ++i) { 329 for (size_t i = 0; i < potential_children.size(); ++i) {
411 if (potential_children[i].empty() || 330 if (potential_children[i].empty() ||
412 potential_children[i].size() <= parent.size()) { 331 potential_children[i].size() <= parent.size()) {
413 result = result || false; 332 result = result || false;
414 } else { 333 } else {
415 size_t domain_diff = FindSubDomainDifference(potential_children[i], 334 size_t domain_diff =
416 parent); 335 FindSubDomainDifference(potential_children[i], parent);
417 if (domain_diff == 1 && potential_children[i][0] != "www") 336 if (domain_diff == 1 && potential_children[i][0] != "www")
418 result = result || true; 337 result = result || true;
419 } 338 }
420 } 339 }
421 return result; 340 return result;
422 } 341 }
423 342
424 bool SSLErrorClassification::IsSubDomainOutsideWildcard( 343 bool ErrorClassification::IsSubDomainOutsideWildcard(
425 const Tokens& host_name_tokens) const { 344 const Tokens& host_name_tokens) const {
426 std::string host_name = request_url_.host(); 345 std::string host_name = request_url_.host();
427 std::vector<std::string> dns_names; 346 std::vector<std::string> dns_names;
428 cert_.GetDNSNames(&dns_names); 347 cert_.GetDNSNames(&dns_names);
429 bool result = false; 348 bool result = false;
430 349
431 // This method requires that the host name be longer than the dns name on 350 // This method requires that the host name be longer than the dns name on
432 // the certificate. 351 // the certificate.
433 for (size_t i = 0; i < dns_names.size(); ++i) { 352 for (size_t i = 0; i < dns_names.size(); ++i) {
434 const std::string& name = dns_names[i]; 353 const std::string& name = dns_names[i];
435 if (name.length() < 2 || name.length() >= host_name.length() || 354 if (name.length() < 2 || name.length() >= host_name.length() ||
436 name.find('\0') != std::string::npos || 355 name.find('\0') != std::string::npos || !IsHostNameKnownTLD(name) ||
437 !IsHostNameKnownTLD(name) 356 name[0] != '*' || name[1] != '.') {
438 || name[0] != '*' || name[1] != '.') {
439 continue; 357 continue;
440 } 358 }
441 359
442 // Move past the "*.". 360 // Move past the "*.".
443 std::string extracted_dns_name = name.substr(2); 361 std::string extracted_dns_name = name.substr(2);
444 if (FindSubDomainDifference( 362 if (FindSubDomainDifference(host_name_tokens,
445 host_name_tokens, Tokenize(extracted_dns_name)) == 2) { 363 Tokenize(extracted_dns_name)) == 2) {
446 return true; 364 return true;
447 } 365 }
448 } 366 }
449 return result; 367 return result;
450 } 368 }
451 369
452 bool SSLErrorClassification::IsCertLikelyFromMultiTenantHosting() const { 370 bool ErrorClassification::IsCertLikelyFromMultiTenantHosting() const {
453 std::string host_name = request_url_.host(); 371 std::string host_name = request_url_.host();
454 std::vector<std::string> dns_names; 372 std::vector<std::string> dns_names;
455 std::vector<std::string> dns_names_domain; 373 std::vector<std::string> dns_names_domain;
456 cert_.GetDNSNames(&dns_names); 374 cert_.GetDNSNames(&dns_names);
457 size_t dns_names_size = dns_names.size(); 375 size_t dns_names_size = dns_names.size();
458 376
459 // If there is only 1 DNS name then it is definitely not a shared certificate. 377 // If there is only 1 DNS name then it is definitely not a shared certificate.
460 if (dns_names_size == 0 || dns_names_size == 1) 378 if (dns_names_size == 0 || dns_names_size == 1)
461 return false; 379 return false;
462 380
463 // Check to see if all the domains in the SAN field in the SSL certificate are 381 // Check to see if all the domains in the SAN field in the SSL certificate are
464 // the same or not. 382 // the same or not.
465 for (size_t i = 0; i < dns_names_size; ++i) { 383 for (size_t i = 0; i < dns_names_size; ++i) {
466 dns_names_domain.push_back( 384 dns_names_domain.push_back(
467 net::registry_controlled_domains:: 385 net::registry_controlled_domains::GetDomainAndRegistry(
468 GetDomainAndRegistry(
469 dns_names[i], 386 dns_names[i],
470 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)); 387 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES));
471 } 388 }
472 for (size_t i = 1; i < dns_names_domain.size(); ++i) { 389 for (size_t i = 1; i < dns_names_domain.size(); ++i) {
473 if (dns_names_domain[i] != dns_names_domain[0]) 390 if (dns_names_domain[i] != dns_names_domain[0])
474 return false; 391 return false;
475 } 392 }
476 393
477 // If the number of DNS names is more than 5 then assume that it is a shared 394 // If the number of DNS names is more than 5 then assume that it is a shared
478 // certificate. 395 // certificate.
(...skipping 11 matching lines...) Expand all
490 for (size_t i = 0; i < dns_names_size; ++i) { 407 for (size_t i = 0; i < dns_names_size; ++i) {
491 for (size_t j = i + 1; j < dns_names_size; ++j) { 408 for (size_t j = i + 1; j < dns_names_size; ++j) {
492 int edit_distance = GetLevensteinDistance(dns_names[i], dns_names[j]); 409 int edit_distance = GetLevensteinDistance(dns_names[i], dns_names[j]);
493 if (edit_distance < kMinimumEditDsitance) 410 if (edit_distance < kMinimumEditDsitance)
494 return false; 411 return false;
495 } 412 }
496 } 413 }
497 return true; 414 return true;
498 } 415 }
499 416
500 bool SSLErrorClassification::IsCertLikelyFromSameDomain() const { 417 bool ErrorClassification::IsCertLikelyFromSameDomain() const {
501 std::string host_name = request_url_.host(); 418 std::string host_name = request_url_.host();
502 std::vector<std::string> dns_names; 419 std::vector<std::string> dns_names;
503 cert_.GetDNSNames(&dns_names); 420 cert_.GetDNSNames(&dns_names);
504 421
505 dns_names.push_back(host_name); 422 dns_names.push_back(host_name);
506 std::vector<std::string> dns_names_domain; 423 std::vector<std::string> dns_names_domain;
507 424
508 for (const std::string& dns_name : dns_names) { 425 for (const std::string& dns_name : dns_names) {
509 dns_names_domain.push_back( 426 dns_names_domain.push_back(
510 net::registry_controlled_domains::GetDomainAndRegistry( 427 net::registry_controlled_domains::GetDomainAndRegistry(
511 dns_name, 428 dns_name,
512 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)); 429 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES));
513 } 430 }
514 431
515 DCHECK(!dns_names_domain.empty()); 432 DCHECK(!dns_names_domain.empty());
516 const std::string& host_name_domain = dns_names_domain.back(); 433 const std::string& host_name_domain = dns_names_domain.back();
517 434
518 // Last element is the original domain. So, excluding it. 435 // Last element is the original domain. So, excluding it.
519 return std::find(dns_names_domain.begin(), dns_names_domain.end() - 1, 436 return std::find(dns_names_domain.begin(), dns_names_domain.end() - 1,
520 host_name_domain) != dns_names_domain.end() - 1; 437 host_name_domain) != dns_names_domain.end() - 1;
521 } 438 }
522 439
523 // static 440 // static
524 bool SSLErrorClassification::IsHostnameNonUniqueOrDotless( 441 bool ErrorClassification::IsHostnameNonUniqueOrDotless(
525 const std::string& hostname) { 442 const std::string& hostname) {
526 return net::IsHostnameNonUnique(hostname) || 443 return net::IsHostnameNonUnique(hostname) ||
527 hostname.find('.') == std::string::npos; 444 hostname.find('.') == std::string::npos;
528 } 445 }
529 446
530 void SSLErrorClassification::Observe( 447 } // namespace ssl_errors
531 int type,
532 const content::NotificationSource& source,
533 const content::NotificationDetails& details) {
534 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
535 // When detection is disabled, captive portal service always sends
536 // RESULT_INTERNET_CONNECTED. Ignore any probe results in that case.
537 if (!captive_portal_detection_enabled_)
538 return;
539 if (type == chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT) {
540 captive_portal_probe_completed_ = true;
541 CaptivePortalService::Results* results =
542 content::Details<CaptivePortalService::Results>(details).ptr();
543 // If a captive portal was detected at any point when the interstitial was
544 // displayed, assume that the interstitial was caused by a captive portal.
545 // Example scenario:
546 // 1- Interstitial displayed and captive portal detected, setting the flag.
547 // 2- Captive portal detection automatically opens portal login page.
548 // 3- User logs in on the portal login page.
549 // A notification will be received here for RESULT_INTERNET_CONNECTED. Make
550 // sure we don't clear the captive protal flag, since the interstitial was
551 // potentially caused by the captive portal.
552 captive_portal_detected_ = captive_portal_detected_ ||
553 (results->result == captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL);
554 // Also keep track of non-HTTP portals and error cases.
555 captive_portal_no_response_ = captive_portal_no_response_ ||
556 (results->result == captive_portal::RESULT_NO_RESPONSE);
557 }
558 #endif
559 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698