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

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: Changes for estark Created 5 years, 2 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/histogram_macros.h" 10 #include "base/metrics/histogram_macros.h"
11 #include "base/strings/string_split.h" 11 #include "base/strings/string_split.h"
12 #include "base/strings/utf_string_conversions.h" 12 #include "base/strings/utf_string_conversions.h"
13 #include "base/time/time.h" 13 #include "base/time/time.h"
14 #include "components/ssl_errors/error_info.h" 14 #include "components/ssl_errors/error_info.h"
15 #include "net/base/net_util.h" 15 #include "net/base/net_util.h"
16 #include "net/base/registry_controlled_domains/registry_controlled_domain.h" 16 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
17 #include "net/cert/x509_cert_types.h" 17 #include "net/cert/x509_cert_types.h"
18 #include "net/cert/x509_certificate.h" 18 #include "net/cert/x509_certificate.h"
19 #include "url/gurl.h" 19 #include "url/gurl.h"
20 20
21 #if defined(OS_WIN) 21 #if defined(OS_WIN)
22 #include "base/win/win_util.h" 22 #include "base/win/win_util.h"
23 #include "base/win/windows_version.h" 23 #include "base/win/windows_version.h"
24 #endif 24 #endif
25 25
26 using base::Time; 26 using base::Time;
27 using base::TimeTicks; 27 using base::TimeTicks;
28 using base::TimeDelta; 28 using base::TimeDelta;
29 29
30 namespace ssl_errors {
30 namespace { 31 namespace {
31 32
32 // Events for UMA. Do not reorder or change! 33 // Events for UMA. Do not reorder or change!
33 enum SSLInterstitialCause { 34 enum SSLInterstitialCause {
34 CLOCK_PAST, 35 CLOCK_PAST,
35 CLOCK_FUTURE, 36 CLOCK_FUTURE,
36 WWW_SUBDOMAIN_MATCH, 37 WWW_SUBDOMAIN_MATCH,
37 SUBDOMAIN_MATCH, 38 SUBDOMAIN_MATCH,
38 SUBDOMAIN_INVERSE_MATCH, 39 SUBDOMAIN_INVERSE_MATCH,
39 SUBDOMAIN_OUTSIDE_WILDCARD, 40 SUBDOMAIN_OUTSIDE_WILDCARD,
(...skipping 11 matching lines...) Expand all
51 void RecordSSLInterstitialCause(bool overridable, SSLInterstitialCause event) { 52 void RecordSSLInterstitialCause(bool overridable, SSLInterstitialCause event) {
52 if (overridable) { 53 if (overridable) {
53 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.cause.overridable", event, 54 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.cause.overridable", event,
54 UNUSED_INTERSTITIAL_CAUSE_ENTRY); 55 UNUSED_INTERSTITIAL_CAUSE_ENTRY);
55 } else { 56 } else {
56 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.cause.nonoverridable", event, 57 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.cause.nonoverridable", event,
57 UNUSED_INTERSTITIAL_CAUSE_ENTRY); 58 UNUSED_INTERSTITIAL_CAUSE_ENTRY);
58 } 59 }
59 } 60 }
60 61
61 int GetLevensteinDistance(const std::string& str1, 62 int GetLevensteinDistance(const std::string& str1, const std::string& str2) {
62 const std::string& str2) {
63 if (str1 == str2) 63 if (str1 == str2)
64 return 0; 64 return 0;
65 if (str1.size() == 0) 65 if (str1.size() == 0)
66 return str2.size(); 66 return str2.size();
67 if (str2.size() == 0) 67 if (str2.size() == 0)
68 return str1.size(); 68 return str1.size();
69 std::vector<int> kFirstRow(str2.size() + 1, 0); 69 std::vector<int> kFirstRow(str2.size() + 1, 0);
70 std::vector<int> kSecondRow(str2.size() + 1, 0); 70 std::vector<int> kSecondRow(str2.size() + 1, 0);
71 71
72 for (size_t i = 0; i < kFirstRow.size(); ++i) 72 for (size_t i = 0; i < kFirstRow.size(); ++i)
73 kFirstRow[i] = i; 73 kFirstRow[i] = i;
74 for (size_t i = 0; i < str1.size(); ++i) { 74 for (size_t i = 0; i < str1.size(); ++i) {
75 kSecondRow[0] = i + 1; 75 kSecondRow[0] = i + 1;
76 for (size_t j = 0; j < str2.size(); ++j) { 76 for (size_t j = 0; j < str2.size(); ++j) {
77 int cost = str1[i] == str2[j] ? 0 : 1; 77 int cost = str1[i] == str2[j] ? 0 : 1;
78 kSecondRow[j+1] = std::min(std::min( 78 kSecondRow[j + 1] =
79 kSecondRow[j] + 1, kFirstRow[j + 1] + 1), kFirstRow[j] + cost); 79 std::min(std::min(kSecondRow[j] + 1, kFirstRow[j + 1] + 1),
80 kFirstRow[j] + cost);
80 } 81 }
81 for (size_t j = 0; j < kFirstRow.size(); j++) 82 for (size_t j = 0; j < kFirstRow.size(); j++)
82 kFirstRow[j] = kSecondRow[j]; 83 kFirstRow[j] = kSecondRow[j];
83 } 84 }
84 return kSecondRow[str2.size()]; 85 return kSecondRow[str2.size()];
85 } 86 }
86 87
88 std::vector<HostnameTokens> GetTokenizedDNSNames(
89 const std::vector<std::string>& dns_names) {
90 std::vector<HostnameTokens> dns_name_tokens;
91 for (const auto& dns_name : dns_names) {
92 HostnameTokens dns_name_token_single;
93 if (dns_name.empty() || dns_name.find('\0') != std::string::npos ||
94 !(IsHostNameKnownTLD(dns_name))) {
95 dns_name_token_single.push_back(std::string());
96 } else {
97 dns_name_token_single = Tokenize(dns_name);
98 }
99 dns_name_tokens.push_back(dns_name_token_single);
100 }
101 return dns_name_tokens;
102 }
103
104 size_t FindSubDomainDifference(const HostnameTokens& potential_subdomain,
105 const HostnameTokens& parent) {
106 // A check to ensure that the number of tokens in the tokenized_parent is
107 // less than the tokenized_potential_subdomain.
108 if (parent.size() >= potential_subdomain.size())
109 return 0;
110
111 size_t tokens_match = 0;
112 size_t diff_size = potential_subdomain.size() - parent.size();
113 for (size_t i = 0; i < parent.size(); ++i) {
114 if (parent[i] == potential_subdomain[i + diff_size])
115 tokens_match++;
116 }
117 if (tokens_match == parent.size())
118 return diff_size;
119 return 0;
120 }
121
87 // The time to use when doing build time operations in browser tests. 122 // The time to use when doing build time operations in browser tests.
88 base::Time g_testing_build_time; 123 base::Time g_testing_build_time;
89 124
90 } // namespace 125 } // namespace
91 126
92 SSLErrorClassification::SSLErrorClassification(const base::Time& current_time, 127 void RecordUMAStatistics(bool overridable,
93 const GURL& url, 128 const base::Time& current_time,
94 int cert_error, 129 const GURL& request_url,
95 const net::X509Certificate& cert) 130 int cert_error,
96 : current_time_(current_time), 131 const net::X509Certificate& cert) {
97 request_url_(url),
98 cert_error_(cert_error),
99 cert_(cert) {}
100
101 SSLErrorClassification::~SSLErrorClassification() { }
102
103 void SSLErrorClassification::RecordUMAStatistics(
104 bool overridable) const {
105 ssl_errors::ErrorInfo::ErrorType type = 132 ssl_errors::ErrorInfo::ErrorType type =
106 ssl_errors::ErrorInfo::NetErrorToErrorType(cert_error_); 133 ssl_errors::ErrorInfo::NetErrorToErrorType(cert_error);
107 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl_error_type", type, 134 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl_error_type", type,
108 ssl_errors::ErrorInfo::END_OF_ENUM); 135 ssl_errors::ErrorInfo::END_OF_ENUM);
109 switch (type) { 136 switch (type) {
110 case ssl_errors::ErrorInfo::CERT_DATE_INVALID: { 137 case ssl_errors::ErrorInfo::CERT_DATE_INVALID: {
111 if (IsUserClockInThePast(base::Time::NowFromSystemTime())) { 138 if (IsUserClockInThePast(base::Time::NowFromSystemTime())) {
112 RecordSSLInterstitialCause(overridable, CLOCK_PAST); 139 RecordSSLInterstitialCause(overridable, CLOCK_PAST);
113 } else if (IsUserClockInTheFuture(base::Time::NowFromSystemTime())) { 140 } else if (IsUserClockInTheFuture(base::Time::NowFromSystemTime())) {
114 RecordSSLInterstitialCause(overridable, CLOCK_FUTURE); 141 RecordSSLInterstitialCause(overridable, CLOCK_FUTURE);
115 } else if (cert_.HasExpired() && 142 } else if (cert.HasExpired() &&
116 (current_time_ - cert_.valid_expiry()).InDays() < 28) { 143 (current_time - cert.valid_expiry()).InDays() < 28) {
117 RecordSSLInterstitialCause(overridable, EXPIRED_RECENTLY); 144 RecordSSLInterstitialCause(overridable, EXPIRED_RECENTLY);
118 } 145 }
119 break; 146 break;
120 } 147 }
121 case ssl_errors::ErrorInfo::CERT_COMMON_NAME_INVALID: { 148 case ssl_errors::ErrorInfo::CERT_COMMON_NAME_INVALID: {
122 std::string host_name = request_url_.host(); 149 std::string host_name = request_url.host();
123 if (IsHostNameKnownTLD(host_name)) { 150 if (IsHostNameKnownTLD(host_name)) {
124 Tokens host_name_tokens = Tokenize(host_name); 151 HostnameTokens host_name_tokens = Tokenize(host_name);
125 if (IsWWWSubDomainMatch()) 152 if (IsWWWSubDomainMatch(request_url, cert))
126 RecordSSLInterstitialCause(overridable, WWW_SUBDOMAIN_MATCH); 153 RecordSSLInterstitialCause(overridable, WWW_SUBDOMAIN_MATCH);
127 if (IsSubDomainOutsideWildcard(host_name_tokens)) 154 if (IsSubDomainOutsideWildcard(request_url, cert))
128 RecordSSLInterstitialCause(overridable, SUBDOMAIN_OUTSIDE_WILDCARD); 155 RecordSSLInterstitialCause(overridable, SUBDOMAIN_OUTSIDE_WILDCARD);
129 std::vector<std::string> dns_names; 156 std::vector<std::string> dns_names;
130 cert_.GetDNSNames(&dns_names); 157 cert.GetDNSNames(&dns_names);
131 std::vector<Tokens> dns_name_tokens = GetTokenizedDNSNames(dns_names); 158 std::vector<HostnameTokens> dns_name_tokens =
159 GetTokenizedDNSNames(dns_names);
132 if (NameUnderAnyNames(host_name_tokens, dns_name_tokens)) 160 if (NameUnderAnyNames(host_name_tokens, dns_name_tokens))
133 RecordSSLInterstitialCause(overridable, SUBDOMAIN_MATCH); 161 RecordSSLInterstitialCause(overridable, SUBDOMAIN_MATCH);
134 if (AnyNamesUnderName(dns_name_tokens, host_name_tokens)) 162 if (AnyNamesUnderName(dns_name_tokens, host_name_tokens))
135 RecordSSLInterstitialCause(overridable, SUBDOMAIN_INVERSE_MATCH); 163 RecordSSLInterstitialCause(overridable, SUBDOMAIN_INVERSE_MATCH);
136 if (IsCertLikelyFromMultiTenantHosting()) 164 if (IsCertLikelyFromMultiTenantHosting(request_url, cert))
137 RecordSSLInterstitialCause(overridable, LIKELY_MULTI_TENANT_HOSTING); 165 RecordSSLInterstitialCause(overridable, LIKELY_MULTI_TENANT_HOSTING);
138 if (IsCertLikelyFromSameDomain()) 166 if (IsCertLikelyFromSameDomain(request_url, cert))
139 RecordSSLInterstitialCause(overridable, LIKELY_SAME_DOMAIN); 167 RecordSSLInterstitialCause(overridable, LIKELY_SAME_DOMAIN);
140 } else { 168 } else {
141 RecordSSLInterstitialCause(overridable, HOST_NAME_NOT_KNOWN_TLD); 169 RecordSSLInterstitialCause(overridable, HOST_NAME_NOT_KNOWN_TLD);
142 } 170 }
143 break; 171 break;
144 } 172 }
145 case ssl_errors::ErrorInfo::CERT_AUTHORITY_INVALID: { 173 case ssl_errors::ErrorInfo::CERT_AUTHORITY_INVALID: {
146 const std::string& hostname = request_url_.HostNoBrackets(); 174 const std::string& hostname = request_url.HostNoBrackets();
147 if (net::IsLocalhost(hostname)) 175 if (net::IsLocalhost(hostname))
148 RecordSSLInterstitialCause(overridable, LOCALHOST); 176 RecordSSLInterstitialCause(overridable, LOCALHOST);
149 if (IsHostnameNonUniqueOrDotless(hostname)) 177 if (IsHostnameNonUniqueOrDotless(hostname))
150 RecordSSLInterstitialCause(overridable, PRIVATE_URL); 178 RecordSSLInterstitialCause(overridable, PRIVATE_URL);
151 if (net::X509Certificate::IsSelfSigned(cert_.os_cert_handle())) 179 if (net::X509Certificate::IsSelfSigned(cert.os_cert_handle()))
152 RecordSSLInterstitialCause(overridable, SELF_SIGNED); 180 RecordSSLInterstitialCause(overridable, SELF_SIGNED);
153 break; 181 break;
154 } 182 }
155 default: 183 default:
156 break; 184 break;
157 } 185 }
158 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.connection_type", 186 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.connection_type",
159 net::NetworkChangeNotifier::GetConnectionType(), 187 net::NetworkChangeNotifier::GetConnectionType(),
160 net::NetworkChangeNotifier::CONNECTION_LAST); 188 net::NetworkChangeNotifier::CONNECTION_LAST);
161 } 189 }
162 190
163 bool SSLErrorClassification::IsUserClockInThePast(const base::Time& time_now) { 191 bool IsUserClockInThePast(const base::Time& time_now) {
164 base::Time build_time; 192 base::Time build_time;
165 if (!g_testing_build_time.is_null()) { 193 if (!g_testing_build_time.is_null()) {
166 build_time = g_testing_build_time; 194 build_time = g_testing_build_time;
167 } else { 195 } else {
168 #if defined(DONT_EMBED_BUILD_METADATA) && !defined(OFFICIAL_BUILD) 196 #if defined(DONT_EMBED_BUILD_METADATA) && !defined(OFFICIAL_BUILD)
169 return false; 197 return false;
170 #else 198 #else
171 build_time = base::GetBuildTime(); 199 build_time = base::GetBuildTime();
172 #endif 200 #endif
173 } 201 }
174 202
175 if (time_now < build_time - base::TimeDelta::FromDays(2)) 203 if (time_now < build_time - base::TimeDelta::FromDays(2))
176 return true; 204 return true;
177 return false; 205 return false;
178 } 206 }
179 207
180 bool SSLErrorClassification::IsUserClockInTheFuture( 208 bool IsUserClockInTheFuture(const base::Time& time_now) {
181 const base::Time& time_now) {
182 base::Time build_time; 209 base::Time build_time;
183 if (!g_testing_build_time.is_null()) { 210 if (!g_testing_build_time.is_null()) {
184 build_time = g_testing_build_time; 211 build_time = g_testing_build_time;
185 } else { 212 } else {
186 #if defined(DONT_EMBED_BUILD_METADATA) && !defined(OFFICIAL_BUILD) 213 #if defined(DONT_EMBED_BUILD_METADATA) && !defined(OFFICIAL_BUILD)
187 return false; 214 return false;
188 #else 215 #else
189 build_time = base::GetBuildTime(); 216 build_time = base::GetBuildTime();
190 #endif 217 #endif
191 } 218 }
192 219
193 if (time_now > build_time + base::TimeDelta::FromDays(365)) 220 if (time_now > build_time + base::TimeDelta::FromDays(365))
194 return true; 221 return true;
195 return false; 222 return false;
196 } 223 }
197 224
198 // static 225 void SetBuildTimeForTesting(const base::Time& testing_time) {
199 void SSLErrorClassification::SetBuildTimeForTesting(
200 const base::Time& testing_time) {
201 g_testing_build_time = testing_time; 226 g_testing_build_time = testing_time;
202 } 227 }
203 228
204 bool SSLErrorClassification::MaybeWindowsLacksSHA256Support() { 229 bool IsHostNameKnownTLD(const std::string& host_name) {
205 #if defined(OS_WIN) 230 size_t tld_length = net::registry_controlled_domains::GetRegistryLength(
206 return !base::win::MaybeHasSHA256Support(); 231 host_name, net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES,
207 #else 232 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
208 return false;
209 #endif
210 }
211
212 bool SSLErrorClassification::IsHostNameKnownTLD(const std::string& host_name) {
213 size_t tld_length =
214 net::registry_controlled_domains::GetRegistryLength(
215 host_name,
216 net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES,
217 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
218 if (tld_length == 0 || tld_length == std::string::npos) 233 if (tld_length == 0 || tld_length == std::string::npos)
219 return false; 234 return false;
220 return true; 235 return true;
221 } 236 }
222 237
223 std::vector<SSLErrorClassification::Tokens> SSLErrorClassification:: 238 HostnameTokens Tokenize(const std::string& name) {
224 GetTokenizedDNSNames(const std::vector<std::string>& dns_names) { 239 return base::SplitString(name, ".", base::KEEP_WHITESPACE,
225 std::vector<std::vector<std::string>> dns_name_tokens; 240 base::SPLIT_WANT_ALL);
226 for (size_t i = 0; i < dns_names.size(); ++i) {
227 std::vector<std::string> dns_name_token_single;
228 if (dns_names[i].empty() || dns_names[i].find('\0') != std::string::npos
229 || !(IsHostNameKnownTLD(dns_names[i]))) {
230 dns_name_token_single.push_back(std::string());
231 } else {
232 dns_name_token_single = Tokenize(dns_names[i]);
233 }
234 dns_name_tokens.push_back(dns_name_token_single);
235 }
236 return dns_name_tokens;
237 }
238
239 size_t SSLErrorClassification::FindSubDomainDifference(
240 const Tokens& potential_subdomain, const Tokens& parent) const {
241 // A check to ensure that the number of tokens in the tokenized_parent is
242 // less than the tokenized_potential_subdomain.
243 if (parent.size() >= potential_subdomain.size())
244 return 0;
245
246 size_t tokens_match = 0;
247 size_t diff_size = potential_subdomain.size() - parent.size();
248 for (size_t i = 0; i < parent.size(); ++i) {
249 if (parent[i] == potential_subdomain[i + diff_size])
250 tokens_match++;
251 }
252 if (tokens_match == parent.size())
253 return diff_size;
254 return 0;
255 }
256
257 SSLErrorClassification::Tokens SSLErrorClassification::
258 Tokenize(const std::string& name) {
259 return base::SplitString(
260 name, ".", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
261 } 241 }
262 242
263 // We accept the inverse case for www for historical reasons. 243 // We accept the inverse case for www for historical reasons.
264 bool SSLErrorClassification::GetWWWSubDomainMatch( 244 bool IsWWWSubDomainMatch(const GURL& request_url,
265 const std::string& host_name, 245 const net::X509Certificate& cert) {
266 const std::vector<std::string>& dns_names, 246 std::string www_host;
267 std::string* www_match_host_name) { 247 std::vector<std::string> dns_names;
248 cert.GetDNSNames(&dns_names);
249 return (GetWWWSubDomainMatch(request_url, dns_names, &www_host));
estark 2015/10/06 02:35:41 nit: unnecessary parens
felt 2015/10/06 03:15:10 Done.
250 }
251
252 bool GetWWWSubDomainMatch(const GURL& request_url,
253 const std::vector<std::string>& dns_names,
254 std::string* www_match_host_name) {
255 const std::string& host_name = request_url.host();
256
268 if (IsHostNameKnownTLD(host_name)) { 257 if (IsHostNameKnownTLD(host_name)) {
269 // Need to account for all possible domains given in the SSL certificate. 258 // Need to account for all possible domains given in the SSL certificate.
270 for (size_t i = 0; i < dns_names.size(); ++i) { 259 for (size_t i = 0; i < dns_names.size(); ++i) {
271 if (dns_names[i].empty() || 260 if (dns_names[i].empty() ||
272 dns_names[i].find('\0') != std::string::npos || 261 dns_names[i].find('\0') != std::string::npos ||
273 dns_names[i].length() == host_name.length() || 262 dns_names[i].length() == host_name.length() ||
274 !IsHostNameKnownTLD(dns_names[i])) { 263 !IsHostNameKnownTLD(dns_names[i])) {
275 continue; 264 continue;
276 } else if (dns_names[i].length() > host_name.length()) { 265 } else if (dns_names[i].length() > host_name.length()) {
277 if (net::StripWWW(base::ASCIIToUTF16(dns_names[i])) == 266 if (net::StripWWW(base::ASCIIToUTF16(dns_names[i])) ==
278 base::ASCIIToUTF16(host_name)) { 267 base::ASCIIToUTF16(host_name)) {
279 *www_match_host_name = dns_names[i]; 268 *www_match_host_name = dns_names[i];
280 return true; 269 return true;
281 } 270 }
282 } else { 271 } else {
283 if (net::StripWWW(base::ASCIIToUTF16(host_name)) == 272 if (net::StripWWW(base::ASCIIToUTF16(host_name)) ==
284 base::ASCIIToUTF16(dns_names[i])) { 273 base::ASCIIToUTF16(dns_names[i])) {
285 *www_match_host_name = dns_names[i]; 274 *www_match_host_name = dns_names[i];
286 return true; 275 return true;
287 } 276 }
288 } 277 }
289 } 278 }
290 } 279 }
291 return false; 280 return false;
292 } 281 }
293 282
294 bool SSLErrorClassification::IsWWWSubDomainMatch() const { 283 bool NameUnderAnyNames(const HostnameTokens& child,
295 const std::string& host_name = request_url_.host(); 284 const std::vector<HostnameTokens>& potential_parents) {
296 std::vector<std::string> dns_names;
297 cert_.GetDNSNames(&dns_names);
298 std::string www_host;
299 return GetWWWSubDomainMatch(host_name, dns_names, &www_host);
300 }
301
302 bool SSLErrorClassification::NameUnderAnyNames(
303 const Tokens& child,
304 const std::vector<Tokens>& potential_parents) const {
305 bool result = false; 285 bool result = false;
306 // Need to account for all the possible domains given in the SSL certificate. 286 // Need to account for all the possible domains given in the SSL certificate.
307 for (size_t i = 0; i < potential_parents.size(); ++i) { 287 for (size_t i = 0; i < potential_parents.size(); ++i) {
308 if (potential_parents[i].empty() || 288 if (potential_parents[i].empty() ||
309 potential_parents[i].size() >= child.size()) { 289 potential_parents[i].size() >= child.size()) {
310 result = result || false; 290 result = result || false;
311 } else { 291 } else {
312 size_t domain_diff = FindSubDomainDifference(child, 292 size_t domain_diff = FindSubDomainDifference(child, potential_parents[i]);
313 potential_parents[i]); 293 if (domain_diff == 1 && child[0] != "www")
314 if (domain_diff == 1 && child[0] != "www")
315 result = result || true; 294 result = result || true;
316 } 295 }
317 } 296 }
318 return result; 297 return result;
319 } 298 }
320 299
321 bool SSLErrorClassification::AnyNamesUnderName( 300 bool AnyNamesUnderName(const std::vector<HostnameTokens>& potential_children,
322 const std::vector<Tokens>& potential_children, 301 const HostnameTokens& parent) {
323 const Tokens& parent) const {
324 bool result = false; 302 bool result = false;
325 // Need to account for all the possible domains given in the SSL certificate. 303 // Need to account for all the possible domains given in the SSL certificate.
326 for (size_t i = 0; i < potential_children.size(); ++i) { 304 for (size_t i = 0; i < potential_children.size(); ++i) {
327 if (potential_children[i].empty() || 305 if (potential_children[i].empty() ||
328 potential_children[i].size() <= parent.size()) { 306 potential_children[i].size() <= parent.size()) {
329 result = result || false; 307 result = result || false;
330 } else { 308 } else {
331 size_t domain_diff = FindSubDomainDifference(potential_children[i], 309 size_t domain_diff =
332 parent); 310 FindSubDomainDifference(potential_children[i], parent);
333 if (domain_diff == 1 && potential_children[i][0] != "www") 311 if (domain_diff == 1 && potential_children[i][0] != "www")
334 result = result || true; 312 result = result || true;
335 } 313 }
336 } 314 }
337 return result; 315 return result;
338 } 316 }
339 317
340 bool SSLErrorClassification::IsSubDomainOutsideWildcard( 318 bool IsSubDomainOutsideWildcard(const GURL& request_url,
341 const Tokens& host_name_tokens) const { 319 const net::X509Certificate& cert) {
342 std::string host_name = request_url_.host(); 320 std::string host_name = request_url.host();
321 HostnameTokens host_name_tokens = Tokenize(host_name);
343 std::vector<std::string> dns_names; 322 std::vector<std::string> dns_names;
344 cert_.GetDNSNames(&dns_names); 323 cert.GetDNSNames(&dns_names);
345 bool result = false; 324 bool result = false;
346 325
347 // This method requires that the host name be longer than the dns name on 326 // This method requires that the host name be longer than the dns name on
348 // the certificate. 327 // the certificate.
349 for (size_t i = 0; i < dns_names.size(); ++i) { 328 for (size_t i = 0; i < dns_names.size(); ++i) {
350 const std::string& name = dns_names[i]; 329 const std::string& name = dns_names[i];
351 if (name.length() < 2 || name.length() >= host_name.length() || 330 if (name.length() < 2 || name.length() >= host_name.length() ||
352 name.find('\0') != std::string::npos || 331 name.find('\0') != std::string::npos || !IsHostNameKnownTLD(name) ||
353 !IsHostNameKnownTLD(name) 332 name[0] != '*' || name[1] != '.') {
354 || name[0] != '*' || name[1] != '.') {
355 continue; 333 continue;
356 } 334 }
357 335
358 // Move past the "*.". 336 // Move past the "*.".
359 std::string extracted_dns_name = name.substr(2); 337 std::string extracted_dns_name = name.substr(2);
360 if (FindSubDomainDifference( 338 if (FindSubDomainDifference(host_name_tokens,
361 host_name_tokens, Tokenize(extracted_dns_name)) == 2) { 339 Tokenize(extracted_dns_name)) == 2) {
362 return true; 340 return true;
363 } 341 }
364 } 342 }
365 return result; 343 return result;
366 } 344 }
367 345
368 bool SSLErrorClassification::IsCertLikelyFromMultiTenantHosting() const { 346 bool IsCertLikelyFromMultiTenantHosting(const GURL& request_url,
369 std::string host_name = request_url_.host(); 347 const net::X509Certificate& cert) {
348 std::string host_name = request_url.host();
370 std::vector<std::string> dns_names; 349 std::vector<std::string> dns_names;
371 std::vector<std::string> dns_names_domain; 350 std::vector<std::string> dns_names_domain;
372 cert_.GetDNSNames(&dns_names); 351 cert.GetDNSNames(&dns_names);
373 size_t dns_names_size = dns_names.size(); 352 size_t dns_names_size = dns_names.size();
374 353
375 // If there is only 1 DNS name then it is definitely not a shared certificate. 354 // If there is only 1 DNS name then it is definitely not a shared certificate.
376 if (dns_names_size == 0 || dns_names_size == 1) 355 if (dns_names_size == 0 || dns_names_size == 1)
377 return false; 356 return false;
378 357
379 // Check to see if all the domains in the SAN field in the SSL certificate are 358 // Check to see if all the domains in the SAN field in the SSL certificate are
380 // the same or not. 359 // the same or not.
381 for (size_t i = 0; i < dns_names_size; ++i) { 360 for (size_t i = 0; i < dns_names_size; ++i) {
382 dns_names_domain.push_back( 361 dns_names_domain.push_back(
383 net::registry_controlled_domains:: 362 net::registry_controlled_domains::GetDomainAndRegistry(
384 GetDomainAndRegistry(
385 dns_names[i], 363 dns_names[i],
386 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)); 364 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES));
387 } 365 }
388 for (size_t i = 1; i < dns_names_domain.size(); ++i) { 366 for (size_t i = 1; i < dns_names_domain.size(); ++i) {
389 if (dns_names_domain[i] != dns_names_domain[0]) 367 if (dns_names_domain[i] != dns_names_domain[0])
390 return false; 368 return false;
391 } 369 }
392 370
393 // If the number of DNS names is more than 5 then assume that it is a shared 371 // If the number of DNS names is more than 5 then assume that it is a shared
394 // certificate. 372 // certificate.
(...skipping 11 matching lines...) Expand all
406 for (size_t i = 0; i < dns_names_size; ++i) { 384 for (size_t i = 0; i < dns_names_size; ++i) {
407 for (size_t j = i + 1; j < dns_names_size; ++j) { 385 for (size_t j = i + 1; j < dns_names_size; ++j) {
408 int edit_distance = GetLevensteinDistance(dns_names[i], dns_names[j]); 386 int edit_distance = GetLevensteinDistance(dns_names[i], dns_names[j]);
409 if (edit_distance < kMinimumEditDsitance) 387 if (edit_distance < kMinimumEditDsitance)
410 return false; 388 return false;
411 } 389 }
412 } 390 }
413 return true; 391 return true;
414 } 392 }
415 393
416 bool SSLErrorClassification::IsCertLikelyFromSameDomain() const { 394 bool IsCertLikelyFromSameDomain(const GURL& request_url,
417 std::string host_name = request_url_.host(); 395 const net::X509Certificate& cert) {
396 std::string host_name = request_url.host();
418 std::vector<std::string> dns_names; 397 std::vector<std::string> dns_names;
419 cert_.GetDNSNames(&dns_names); 398 cert.GetDNSNames(&dns_names);
420 399
421 dns_names.push_back(host_name); 400 dns_names.push_back(host_name);
422 std::vector<std::string> dns_names_domain; 401 std::vector<std::string> dns_names_domain;
423 402
424 for (const std::string& dns_name : dns_names) { 403 for (const std::string& dns_name : dns_names) {
425 dns_names_domain.push_back( 404 dns_names_domain.push_back(
426 net::registry_controlled_domains::GetDomainAndRegistry( 405 net::registry_controlled_domains::GetDomainAndRegistry(
427 dns_name, 406 dns_name,
428 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)); 407 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES));
429 } 408 }
430 409
431 DCHECK(!dns_names_domain.empty()); 410 DCHECK(!dns_names_domain.empty());
432 const std::string& host_name_domain = dns_names_domain.back(); 411 const std::string& host_name_domain = dns_names_domain.back();
433 412
434 // Last element is the original domain. So, excluding it. 413 // Last element is the original domain. So, excluding it.
435 return std::find(dns_names_domain.begin(), dns_names_domain.end() - 1, 414 return std::find(dns_names_domain.begin(), dns_names_domain.end() - 1,
436 host_name_domain) != dns_names_domain.end() - 1; 415 host_name_domain) != dns_names_domain.end() - 1;
437 } 416 }
438 417
439 // static 418 bool IsHostnameNonUniqueOrDotless(const std::string& hostname) {
440 bool SSLErrorClassification::IsHostnameNonUniqueOrDotless(
441 const std::string& hostname) {
442 return net::IsHostnameNonUnique(hostname) || 419 return net::IsHostnameNonUnique(hostname) ||
443 hostname.find('.') == std::string::npos; 420 hostname.find('.') == std::string::npos;
444 } 421 }
422
423 } // namespace ssl_errors
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698