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

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

Issue 2804883005: Update SSL error handling code to account for Subject CN deprecation (Closed)
Patch Set: Created 3 years, 8 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 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>
(...skipping 20 matching lines...) Expand all
31 #include "base/win/windows_version.h" 31 #include "base/win/windows_version.h"
32 #endif 32 #endif
33 33
34 using base::Time; 34 using base::Time;
35 using base::TimeTicks; 35 using base::TimeTicks;
36 using base::TimeDelta; 36 using base::TimeDelta;
37 37
38 namespace ssl_errors { 38 namespace ssl_errors {
39 namespace { 39 namespace {
40 40
41 // Events for UMA. Do not reorder or change!
42 enum SSLInterstitialCause {
43 CLOCK_PAST,
44 CLOCK_FUTURE,
45 WWW_SUBDOMAIN_MATCH,
46 SUBDOMAIN_MATCH,
47 SUBDOMAIN_INVERSE_MATCH,
48 SUBDOMAIN_OUTSIDE_WILDCARD,
49 HOST_NAME_NOT_KNOWN_TLD,
50 LIKELY_MULTI_TENANT_HOSTING,
51 LOCALHOST,
52 PRIVATE_URL,
53 AUTHORITY_ERROR_CAPTIVE_PORTAL, // Deprecated in M47.
54 SELF_SIGNED,
55 EXPIRED_RECENTLY,
56 LIKELY_SAME_DOMAIN,
57 UNUSED_INTERSTITIAL_CAUSE_ENTRY,
58 };
59
60 void RecordSSLInterstitialCause(bool overridable, SSLInterstitialCause event) { 41 void RecordSSLInterstitialCause(bool overridable, SSLInterstitialCause event) {
61 if (overridable) { 42 if (overridable) {
62 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.cause.overridable", event, 43 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.cause.overridable", event,
63 UNUSED_INTERSTITIAL_CAUSE_ENTRY); 44 SSL_INTERSTITIAL_CAUSE_MAX);
64 } else { 45 } else {
65 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.cause.nonoverridable", event, 46 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl.cause.nonoverridable", event,
66 UNUSED_INTERSTITIAL_CAUSE_ENTRY); 47 SSL_INTERSTITIAL_CAUSE_MAX);
67 } 48 }
68 } 49 }
69 50
70 std::vector<HostnameTokens> GetTokenizedDNSNames( 51 std::vector<HostnameTokens> GetTokenizedDNSNames(
71 const std::vector<std::string>& dns_names) { 52 const std::vector<std::string>& dns_names) {
72 std::vector<HostnameTokens> dns_name_tokens; 53 std::vector<HostnameTokens> dns_name_tokens;
73 for (const auto& dns_name : dns_names) { 54 for (const auto& dns_name : dns_names) {
74 HostnameTokens dns_name_token_single; 55 HostnameTokens dns_name_token_single;
75 if (dns_name.empty() || dns_name.find('\0') != std::string::npos || 56 if (dns_name.empty() || dns_name.find('\0') != std::string::npos ||
76 !(HostNameHasKnownTLD(dns_name))) { 57 !(HostNameHasKnownTLD(dns_name))) {
(...skipping 25 matching lines...) Expand all
102 return -1; 83 return -1;
103 } 84 }
104 return diff_size; 85 return diff_size;
105 } 86 }
106 87
107 // We accept the inverse case for www for historical reasons. 88 // We accept the inverse case for www for historical reasons.
108 bool IsWWWSubDomainMatch(const GURL& request_url, 89 bool IsWWWSubDomainMatch(const GURL& request_url,
109 const net::X509Certificate& cert) { 90 const net::X509Certificate& cert) {
110 std::string www_host; 91 std::string www_host;
111 std::vector<std::string> dns_names; 92 std::vector<std::string> dns_names;
112 cert.GetDNSNames(&dns_names); 93 cert.GetSubjectAltName(&dns_names, nullptr);
113 return GetWWWSubDomainMatch(request_url, dns_names, &www_host); 94 return GetWWWSubDomainMatch(request_url, dns_names, &www_host);
114 } 95 }
115 96
116 // The time to use when doing build time operations in browser tests. 97 // The time to use when doing build time operations in browser tests.
117 base::LazyInstance<base::Time> g_testing_build_time = LAZY_INSTANCE_INITIALIZER; 98 base::LazyInstance<base::Time> g_testing_build_time = LAZY_INSTANCE_INITIALIZER;
118 99
119 } // namespace 100 } // namespace
120 101
121 static ssl_errors::ErrorInfo::ErrorType RecordErrorType(int cert_error) { 102 static ssl_errors::ErrorInfo::ErrorType RecordErrorType(int cert_error) {
122 ssl_errors::ErrorInfo::ErrorType error_type = 103 ssl_errors::ErrorInfo::ErrorType error_type =
(...skipping 18 matching lines...) Expand all
141 // Note: not reached when displaying the bad clock interstitial. 122 // Note: not reached when displaying the bad clock interstitial.
142 // See |RecordUMAStatisticsForClockInterstitial| below. 123 // See |RecordUMAStatisticsForClockInterstitial| below.
143 if (cert.HasExpired() && 124 if (cert.HasExpired() &&
144 (current_time - cert.valid_expiry()).InDays() < 28) { 125 (current_time - cert.valid_expiry()).InDays() < 28) {
145 RecordSSLInterstitialCause(overridable, EXPIRED_RECENTLY); 126 RecordSSLInterstitialCause(overridable, EXPIRED_RECENTLY);
146 } 127 }
147 break; 128 break;
148 } 129 }
149 case ssl_errors::ErrorInfo::CERT_COMMON_NAME_INVALID: { 130 case ssl_errors::ErrorInfo::CERT_COMMON_NAME_INVALID: {
150 std::string host_name = request_url.host(); 131 std::string host_name = request_url.host();
132 std::vector<std::string> dns_names;
133 cert.GetSubjectAltName(&dns_names, nullptr);
134 std::vector<HostnameTokens> dns_name_tokens =
135 GetTokenizedDNSNames(dns_names);
136
137 if (dns_names.empty())
138 RecordSSLInterstitialCause(overridable, NO_SUBJECT_ALT_NAME);
139
151 if (HostNameHasKnownTLD(host_name)) { 140 if (HostNameHasKnownTLD(host_name)) {
152 HostnameTokens host_name_tokens = Tokenize(host_name); 141 HostnameTokens host_name_tokens = Tokenize(host_name);
153 if (IsWWWSubDomainMatch(request_url, cert)) 142 if (IsWWWSubDomainMatch(request_url, cert))
154 RecordSSLInterstitialCause(overridable, WWW_SUBDOMAIN_MATCH); 143 RecordSSLInterstitialCause(overridable, WWW_SUBDOMAIN_MATCH2);
155 if (IsSubDomainOutsideWildcard(request_url, cert)) 144 if (IsSubDomainOutsideWildcard(request_url, cert))
156 RecordSSLInterstitialCause(overridable, SUBDOMAIN_OUTSIDE_WILDCARD); 145 RecordSSLInterstitialCause(overridable, SUBDOMAIN_OUTSIDE_WILDCARD2);
157 std::vector<std::string> dns_names;
158 cert.GetDNSNames(&dns_names);
159 std::vector<HostnameTokens> dns_name_tokens =
160 GetTokenizedDNSNames(dns_names);
161 if (NameUnderAnyNames(host_name_tokens, dns_name_tokens)) 146 if (NameUnderAnyNames(host_name_tokens, dns_name_tokens))
162 RecordSSLInterstitialCause(overridable, SUBDOMAIN_MATCH); 147 RecordSSLInterstitialCause(overridable, SUBDOMAIN_MATCH2);
163 if (AnyNamesUnderName(dns_name_tokens, host_name_tokens)) 148 if (AnyNamesUnderName(dns_name_tokens, host_name_tokens))
164 RecordSSLInterstitialCause(overridable, SUBDOMAIN_INVERSE_MATCH); 149 RecordSSLInterstitialCause(overridable, SUBDOMAIN_INVERSE_MATCH2);
165 if (IsCertLikelyFromMultiTenantHosting(request_url, cert)) 150 if (IsCertLikelyFromMultiTenantHosting(request_url, cert))
166 RecordSSLInterstitialCause(overridable, LIKELY_MULTI_TENANT_HOSTING); 151 RecordSSLInterstitialCause(overridable, LIKELY_MULTI_TENANT_HOSTING2);
167 if (IsCertLikelyFromSameDomain(request_url, cert)) 152 if (IsCertLikelyFromSameDomain(request_url, cert))
168 RecordSSLInterstitialCause(overridable, LIKELY_SAME_DOMAIN); 153 RecordSSLInterstitialCause(overridable, LIKELY_SAME_DOMAIN2);
169 } else { 154 } else {
170 RecordSSLInterstitialCause(overridable, HOST_NAME_NOT_KNOWN_TLD); 155 RecordSSLInterstitialCause(overridable, HOST_NAME_NOT_KNOWN_TLD);
171 } 156 }
172 break; 157 break;
173 } 158 }
174 case ssl_errors::ErrorInfo::CERT_AUTHORITY_INVALID: { 159 case ssl_errors::ErrorInfo::CERT_AUTHORITY_INVALID: {
175 const std::string& hostname = request_url.HostNoBrackets(); 160 const std::string& hostname = request_url.HostNoBrackets();
176 if (net::IsLocalhost(hostname)) 161 if (net::IsLocalhost(hostname))
177 RecordSSLInterstitialCause(overridable, LOCALHOST); 162 RecordSSLInterstitialCause(overridable, LOCALHOST);
178 if (IsHostnameNonUniqueOrDotless(hostname)) 163 if (IsHostnameNonUniqueOrDotless(hostname))
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after
375 } 360 }
376 } 361 }
377 return row[str2.size()]; 362 return row[str2.size()];
378 } 363 }
379 364
380 bool IsSubDomainOutsideWildcard(const GURL& request_url, 365 bool IsSubDomainOutsideWildcard(const GURL& request_url,
381 const net::X509Certificate& cert) { 366 const net::X509Certificate& cert) {
382 std::string host_name = request_url.host(); 367 std::string host_name = request_url.host();
383 HostnameTokens host_name_tokens = Tokenize(host_name); 368 HostnameTokens host_name_tokens = Tokenize(host_name);
384 std::vector<std::string> dns_names; 369 std::vector<std::string> dns_names;
385 cert.GetDNSNames(&dns_names); 370 cert.GetSubjectAltName(&dns_names, nullptr);
386 bool result = false; 371 bool result = false;
387 372
388 // This method requires that the host name be longer than the dns name on 373 // This method requires that the host name be longer than the dns name on
389 // the certificate. 374 // the certificate.
390 for (const auto& dns_name : dns_names) { 375 for (const auto& dns_name : dns_names) {
391 if (dns_name.length() < 2 || dns_name.length() >= host_name.length() || 376 if (dns_name.length() < 2 || dns_name.length() >= host_name.length() ||
392 dns_name.find('\0') != std::string::npos || 377 dns_name.find('\0') != std::string::npos ||
393 !HostNameHasKnownTLD(dns_name) || dns_name[0] != '*' || 378 !HostNameHasKnownTLD(dns_name) || dns_name[0] != '*' ||
394 dns_name[1] != '.') { 379 dns_name[1] != '.') {
395 continue; 380 continue;
396 } 381 }
397 382
398 // Move past the "*.". 383 // Move past the "*.".
399 std::string extracted_dns_name = dns_name.substr(2); 384 std::string extracted_dns_name = dns_name.substr(2);
400 if (FindSubdomainDifference(host_name_tokens, 385 if (FindSubdomainDifference(host_name_tokens,
401 Tokenize(extracted_dns_name)) == 2) { 386 Tokenize(extracted_dns_name)) == 2) {
402 return true; 387 return true;
403 } 388 }
404 } 389 }
405 return result; 390 return result;
406 } 391 }
407 392
408 bool IsCertLikelyFromMultiTenantHosting(const GURL& request_url, 393 bool IsCertLikelyFromMultiTenantHosting(const GURL& request_url,
409 const net::X509Certificate& cert) { 394 const net::X509Certificate& cert) {
410 std::string host_name = request_url.host(); 395 std::string host_name = request_url.host();
411 std::vector<std::string> dns_names; 396 std::vector<std::string> dns_names;
412 std::vector<std::string> dns_names_domain; 397 std::vector<std::string> dns_names_domain;
413 cert.GetDNSNames(&dns_names); 398 cert.GetSubjectAltName(&dns_names, nullptr);
414 size_t dns_names_size = dns_names.size(); 399 size_t dns_names_size = dns_names.size();
415 400
416 // If there is only 1 DNS name then it is definitely not a shared certificate. 401 // If there is only 1 DNS name then it is definitely not a shared certificate.
417 if (dns_names_size == 0 || dns_names_size == 1) 402 if (dns_names_size == 0 || dns_names_size == 1)
418 return false; 403 return false;
419 404
420 // Check to see if all the domains in the SAN field in the SSL certificate are 405 // Check to see if all the domains in the SAN field in the SSL certificate are
421 // the same or not. 406 // the same or not.
422 for (size_t i = 0; i < dns_names_size; ++i) { 407 for (size_t i = 0; i < dns_names_size; ++i) {
423 dns_names_domain.push_back( 408 dns_names_domain.push_back(
(...skipping 26 matching lines...) Expand all
450 return false; 435 return false;
451 } 436 }
452 } 437 }
453 return true; 438 return true;
454 } 439 }
455 440
456 bool IsCertLikelyFromSameDomain(const GURL& request_url, 441 bool IsCertLikelyFromSameDomain(const GURL& request_url,
457 const net::X509Certificate& cert) { 442 const net::X509Certificate& cert) {
458 std::string host_name = request_url.host(); 443 std::string host_name = request_url.host();
459 std::vector<std::string> dns_names; 444 std::vector<std::string> dns_names;
460 cert.GetDNSNames(&dns_names); 445 cert.GetSubjectAltName(&dns_names, nullptr);
446 if (dns_names.empty())
447 return false;
461 448
462 dns_names.push_back(host_name); 449 dns_names.push_back(host_name);
463 std::vector<std::string> dns_names_domain; 450 std::vector<std::string> dns_names_domain;
464 451
465 for (const std::string& dns_name : dns_names) { 452 for (const std::string& dns_name : dns_names) {
466 dns_names_domain.push_back( 453 dns_names_domain.push_back(
467 net::registry_controlled_domains::GetDomainAndRegistry( 454 net::registry_controlled_domains::GetDomainAndRegistry(
468 dns_name, 455 dns_name,
469 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)); 456 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES));
470 } 457 }
471 458
472 DCHECK(!dns_names_domain.empty()); 459 DCHECK(!dns_names_domain.empty());
473 const std::string& host_name_domain = dns_names_domain.back(); 460 const std::string& host_name_domain = dns_names_domain.back();
474 461
475 // Last element is the original domain. So, excluding it. 462 // Last element is the original domain. So, excluding it.
476 return std::find(dns_names_domain.begin(), dns_names_domain.end() - 1, 463 return std::find(dns_names_domain.begin(), dns_names_domain.end() - 1,
477 host_name_domain) != dns_names_domain.end() - 1; 464 host_name_domain) != dns_names_domain.end() - 1;
478 } 465 }
479 466
480 bool IsHostnameNonUniqueOrDotless(const std::string& hostname) { 467 bool IsHostnameNonUniqueOrDotless(const std::string& hostname) {
481 return net::IsHostnameNonUnique(hostname) || 468 return net::IsHostnameNonUnique(hostname) ||
482 hostname.find('.') == std::string::npos; 469 hostname.find('.') == std::string::npos;
483 } 470 }
484 471
485 } // namespace ssl_errors 472 } // namespace ssl_errors
OLDNEW
« no previous file with comments | « components/ssl_errors/error_classification.h ('k') | components/ssl_errors/error_classification_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698