Chromium Code Reviews| Index: components/ssl_errors/error_classification.cc | 
| diff --git a/chrome/browser/ssl/ssl_error_classification.cc b/components/ssl_errors/error_classification.cc | 
| similarity index 67% | 
| rename from chrome/browser/ssl/ssl_error_classification.cc | 
| rename to components/ssl_errors/error_classification.cc | 
| index a93427463247d6d02fded77901c96f64d56d1866..a5dbf1c7ab14cf4c1c78bdb013b6d32b552270b7 100644 | 
| --- a/chrome/browser/ssl/ssl_error_classification.cc | 
| +++ b/components/ssl_errors/error_classification.cc | 
| @@ -1,10 +1,10 @@ | 
| -// Copyright 2014 The Chromium Authors. All rights reserved. | 
| +// Copyright 2015 The Chromium Authors. All rights reserved. | 
| // Use of this source code is governed by a BSD-style license that can be | 
| // found in the LICENSE file. | 
| -#include <vector> | 
| +#include "components/ssl_errors/error_classification.h" | 
| -#include "chrome/browser/ssl/ssl_error_classification.h" | 
| +#include <vector> | 
| #include "base/build_time.h" | 
| #include "base/metrics/histogram_macros.h" | 
| @@ -27,6 +27,7 @@ using base::Time; | 
| using base::TimeTicks; | 
| using base::TimeDelta; | 
| +namespace ssl_errors { | 
| namespace { | 
| // Events for UMA. Do not reorder or change! | 
| @@ -58,8 +59,7 @@ void RecordSSLInterstitialCause(bool overridable, SSLInterstitialCause event) { | 
| } | 
| } | 
| -int GetLevensteinDistance(const std::string& str1, | 
| - const std::string& str2) { | 
| +int GetLevensteinDistance(const std::string& str1, const std::string& str2) { | 
| if (str1 == str2) | 
| return 0; | 
| if (str1.size() == 0) | 
| @@ -75,8 +75,9 @@ int GetLevensteinDistance(const std::string& str1, | 
| kSecondRow[0] = i + 1; | 
| for (size_t j = 0; j < str2.size(); ++j) { | 
| int cost = str1[i] == str2[j] ? 0 : 1; | 
| - kSecondRow[j+1] = std::min(std::min( | 
| - kSecondRow[j] + 1, kFirstRow[j + 1] + 1), kFirstRow[j] + cost); | 
| + kSecondRow[j + 1] = | 
| + std::min(std::min(kSecondRow[j] + 1, kFirstRow[j + 1] + 1), | 
| + kFirstRow[j] + cost); | 
| } | 
| for (size_t j = 0; j < kFirstRow.size(); j++) | 
| kFirstRow[j] = kSecondRow[j]; | 
| @@ -84,26 +85,52 @@ int GetLevensteinDistance(const std::string& str1, | 
| return kSecondRow[str2.size()]; | 
| } | 
| -// The time to use when doing build time operations in browser tests. | 
| -base::Time g_testing_build_time; | 
| +std::vector<HostnameTokens> GetTokenizedDNSNames( | 
| + const std::vector<std::string>& dns_names) { | 
| + std::vector<HostnameTokens> dns_name_tokens; | 
| + for (const auto& dns_name : dns_names) { | 
| + HostnameTokens dns_name_token_single; | 
| + if (dns_name.empty() || dns_name.find('\0') != std::string::npos || | 
| + !(IsHostNameKnownTLD(dns_name))) { | 
| + dns_name_token_single.push_back(std::string()); | 
| + } else { | 
| + dns_name_token_single = Tokenize(dns_name); | 
| + } | 
| + dns_name_tokens.push_back(dns_name_token_single); | 
| + } | 
| + return dns_name_tokens; | 
| +} | 
| -} // namespace | 
| +size_t FindSubDomainDifference(const HostnameTokens& potential_subdomain, | 
| + const HostnameTokens& parent) { | 
| + // A check to ensure that the number of tokens in the tokenized_parent is | 
| + // less than the tokenized_potential_subdomain. | 
| + if (parent.size() >= potential_subdomain.size()) | 
| + return 0; | 
| -SSLErrorClassification::SSLErrorClassification(const base::Time& current_time, | 
| - const GURL& url, | 
| - int cert_error, | 
| - const net::X509Certificate& cert) | 
| - : current_time_(current_time), | 
| - request_url_(url), | 
| - cert_error_(cert_error), | 
| - cert_(cert) {} | 
| + size_t tokens_match = 0; | 
| + size_t diff_size = potential_subdomain.size() - parent.size(); | 
| + for (size_t i = 0; i < parent.size(); ++i) { | 
| + if (parent[i] == potential_subdomain[i + diff_size]) | 
| + tokens_match++; | 
| + } | 
| + if (tokens_match == parent.size()) | 
| + return diff_size; | 
| + return 0; | 
| +} | 
| -SSLErrorClassification::~SSLErrorClassification() { } | 
| +// The time to use when doing build time operations in browser tests. | 
| +base::Time g_testing_build_time; | 
| -void SSLErrorClassification::RecordUMAStatistics( | 
| - bool overridable) const { | 
| +} // namespace | 
| + | 
| +void RecordUMAStatistics(bool overridable, | 
| + const base::Time& current_time, | 
| + const GURL& request_url, | 
| + int cert_error, | 
| + const net::X509Certificate& cert) { | 
| ssl_errors::ErrorInfo::ErrorType type = | 
| - ssl_errors::ErrorInfo::NetErrorToErrorType(cert_error_); | 
| + ssl_errors::ErrorInfo::NetErrorToErrorType(cert_error); | 
| UMA_HISTOGRAM_ENUMERATION("interstitial.ssl_error_type", type, | 
| ssl_errors::ErrorInfo::END_OF_ENUM); | 
| switch (type) { | 
| @@ -112,43 +139,44 @@ void SSLErrorClassification::RecordUMAStatistics( | 
| RecordSSLInterstitialCause(overridable, CLOCK_PAST); | 
| } else if (IsUserClockInTheFuture(base::Time::NowFromSystemTime())) { | 
| RecordSSLInterstitialCause(overridable, CLOCK_FUTURE); | 
| - } else if (cert_.HasExpired() && | 
| - (current_time_ - cert_.valid_expiry()).InDays() < 28) { | 
| + } else if (cert.HasExpired() && | 
| + (current_time - cert.valid_expiry()).InDays() < 28) { | 
| RecordSSLInterstitialCause(overridable, EXPIRED_RECENTLY); | 
| } | 
| break; | 
| } | 
| case ssl_errors::ErrorInfo::CERT_COMMON_NAME_INVALID: { | 
| - std::string host_name = request_url_.host(); | 
| + std::string host_name = request_url.host(); | 
| if (IsHostNameKnownTLD(host_name)) { | 
| - Tokens host_name_tokens = Tokenize(host_name); | 
| - if (IsWWWSubDomainMatch()) | 
| + HostnameTokens host_name_tokens = Tokenize(host_name); | 
| + if (IsWWWSubDomainMatch(request_url, cert)) | 
| RecordSSLInterstitialCause(overridable, WWW_SUBDOMAIN_MATCH); | 
| - if (IsSubDomainOutsideWildcard(host_name_tokens)) | 
| + if (IsSubDomainOutsideWildcard(request_url, cert)) | 
| RecordSSLInterstitialCause(overridable, SUBDOMAIN_OUTSIDE_WILDCARD); | 
| std::vector<std::string> dns_names; | 
| - cert_.GetDNSNames(&dns_names); | 
| - std::vector<Tokens> dns_name_tokens = GetTokenizedDNSNames(dns_names); | 
| + cert.GetDNSNames(&dns_names); | 
| + std::vector<HostnameTokens> dns_name_tokens = | 
| + GetTokenizedDNSNames(dns_names); | 
| if (NameUnderAnyNames(host_name_tokens, dns_name_tokens)) | 
| RecordSSLInterstitialCause(overridable, SUBDOMAIN_MATCH); | 
| if (AnyNamesUnderName(dns_name_tokens, host_name_tokens)) | 
| RecordSSLInterstitialCause(overridable, SUBDOMAIN_INVERSE_MATCH); | 
| - if (IsCertLikelyFromMultiTenantHosting()) | 
| + if (IsCertLikelyFromMultiTenantHosting(request_url, cert)) | 
| RecordSSLInterstitialCause(overridable, LIKELY_MULTI_TENANT_HOSTING); | 
| - if (IsCertLikelyFromSameDomain()) | 
| + if (IsCertLikelyFromSameDomain(request_url, cert)) | 
| RecordSSLInterstitialCause(overridable, LIKELY_SAME_DOMAIN); | 
| } else { | 
| - RecordSSLInterstitialCause(overridable, HOST_NAME_NOT_KNOWN_TLD); | 
| + RecordSSLInterstitialCause(overridable, HOST_NAME_NOT_KNOWN_TLD); | 
| } | 
| break; | 
| } | 
| case ssl_errors::ErrorInfo::CERT_AUTHORITY_INVALID: { | 
| - const std::string& hostname = request_url_.HostNoBrackets(); | 
| + const std::string& hostname = request_url.HostNoBrackets(); | 
| if (net::IsLocalhost(hostname)) | 
| RecordSSLInterstitialCause(overridable, LOCALHOST); | 
| if (IsHostnameNonUniqueOrDotless(hostname)) | 
| RecordSSLInterstitialCause(overridable, PRIVATE_URL); | 
| - if (net::X509Certificate::IsSelfSigned(cert_.os_cert_handle())) | 
| + if (net::X509Certificate::IsSelfSigned(cert.os_cert_handle())) | 
| RecordSSLInterstitialCause(overridable, SELF_SIGNED); | 
| break; | 
| } | 
| @@ -160,7 +188,7 @@ void SSLErrorClassification::RecordUMAStatistics( | 
| net::NetworkChangeNotifier::CONNECTION_LAST); | 
| } | 
| -bool SSLErrorClassification::IsUserClockInThePast(const base::Time& time_now) { | 
| +bool IsUserClockInThePast(const base::Time& time_now) { | 
| base::Time build_time; | 
| if (!g_testing_build_time.is_null()) { | 
| build_time = g_testing_build_time; | 
| @@ -177,8 +205,7 @@ bool SSLErrorClassification::IsUserClockInThePast(const base::Time& time_now) { | 
| return false; | 
| } | 
| -bool SSLErrorClassification::IsUserClockInTheFuture( | 
| - const base::Time& time_now) { | 
| +bool IsUserClockInTheFuture(const base::Time& time_now) { | 
| base::Time build_time; | 
| if (!g_testing_build_time.is_null()) { | 
| build_time = g_testing_build_time; | 
| @@ -195,76 +222,38 @@ bool SSLErrorClassification::IsUserClockInTheFuture( | 
| return false; | 
| } | 
| -// static | 
| -void SSLErrorClassification::SetBuildTimeForTesting( | 
| - const base::Time& testing_time) { | 
| +void SetBuildTimeForTesting(const base::Time& testing_time) { | 
| g_testing_build_time = testing_time; | 
| } | 
| -bool SSLErrorClassification::MaybeWindowsLacksSHA256Support() { | 
| -#if defined(OS_WIN) | 
| - return !base::win::MaybeHasSHA256Support(); | 
| -#else | 
| - return false; | 
| -#endif | 
| -} | 
| - | 
| -bool SSLErrorClassification::IsHostNameKnownTLD(const std::string& host_name) { | 
| - size_t tld_length = | 
| - net::registry_controlled_domains::GetRegistryLength( | 
| - host_name, | 
| - net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES, | 
| - net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); | 
| +bool IsHostNameKnownTLD(const std::string& host_name) { | 
| + size_t tld_length = net::registry_controlled_domains::GetRegistryLength( | 
| + host_name, net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES, | 
| + net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); | 
| if (tld_length == 0 || tld_length == std::string::npos) | 
| return false; | 
| return true; | 
| } | 
| -std::vector<SSLErrorClassification::Tokens> SSLErrorClassification:: | 
| -GetTokenizedDNSNames(const std::vector<std::string>& dns_names) { | 
| - std::vector<std::vector<std::string>> dns_name_tokens; | 
| - for (size_t i = 0; i < dns_names.size(); ++i) { | 
| - std::vector<std::string> dns_name_token_single; | 
| - if (dns_names[i].empty() || dns_names[i].find('\0') != std::string::npos | 
| - || !(IsHostNameKnownTLD(dns_names[i]))) { | 
| - dns_name_token_single.push_back(std::string()); | 
| - } else { | 
| - dns_name_token_single = Tokenize(dns_names[i]); | 
| - } | 
| - dns_name_tokens.push_back(dns_name_token_single); | 
| - } | 
| - return dns_name_tokens; | 
| +HostnameTokens Tokenize(const std::string& name) { | 
| + return base::SplitString(name, ".", base::KEEP_WHITESPACE, | 
| + base::SPLIT_WANT_ALL); | 
| } | 
| -size_t SSLErrorClassification::FindSubDomainDifference( | 
| - const Tokens& potential_subdomain, const Tokens& parent) const { | 
| - // A check to ensure that the number of tokens in the tokenized_parent is | 
| - // less than the tokenized_potential_subdomain. | 
| - if (parent.size() >= potential_subdomain.size()) | 
| - return 0; | 
| - | 
| - size_t tokens_match = 0; | 
| - size_t diff_size = potential_subdomain.size() - parent.size(); | 
| - for (size_t i = 0; i < parent.size(); ++i) { | 
| - if (parent[i] == potential_subdomain[i + diff_size]) | 
| - tokens_match++; | 
| - } | 
| - if (tokens_match == parent.size()) | 
| - return diff_size; | 
| - return 0; | 
| +// We accept the inverse case for www for historical reasons. | 
| +bool IsWWWSubDomainMatch(const GURL& request_url, | 
| + const net::X509Certificate& cert) { | 
| + std::string www_host; | 
| + std::vector<std::string> dns_names; | 
| + cert.GetDNSNames(&dns_names); | 
| + 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.
 
 | 
| } | 
| -SSLErrorClassification::Tokens SSLErrorClassification:: | 
| -Tokenize(const std::string& name) { | 
| - return base::SplitString( | 
| - name, ".", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL); | 
| -} | 
| +bool GetWWWSubDomainMatch(const GURL& request_url, | 
| + const std::vector<std::string>& dns_names, | 
| + std::string* www_match_host_name) { | 
| + const std::string& host_name = request_url.host(); | 
| -// We accept the inverse case for www for historical reasons. | 
| -bool SSLErrorClassification::GetWWWSubDomainMatch( | 
| - const std::string& host_name, | 
| - const std::vector<std::string>& dns_names, | 
| - std::string* www_match_host_name) { | 
| if (IsHostNameKnownTLD(host_name)) { | 
| // Need to account for all possible domains given in the SSL certificate. | 
| for (size_t i = 0; i < dns_names.size(); ++i) { | 
| @@ -291,17 +280,8 @@ bool SSLErrorClassification::GetWWWSubDomainMatch( | 
| return false; | 
| } | 
| -bool SSLErrorClassification::IsWWWSubDomainMatch() const { | 
| - const std::string& host_name = request_url_.host(); | 
| - std::vector<std::string> dns_names; | 
| - cert_.GetDNSNames(&dns_names); | 
| - std::string www_host; | 
| - return GetWWWSubDomainMatch(host_name, dns_names, &www_host); | 
| -} | 
| - | 
| -bool SSLErrorClassification::NameUnderAnyNames( | 
| - const Tokens& child, | 
| - const std::vector<Tokens>& potential_parents) const { | 
| +bool NameUnderAnyNames(const HostnameTokens& child, | 
| + const std::vector<HostnameTokens>& potential_parents) { | 
| bool result = false; | 
| // Need to account for all the possible domains given in the SSL certificate. | 
| for (size_t i = 0; i < potential_parents.size(); ++i) { | 
| @@ -309,18 +289,16 @@ bool SSLErrorClassification::NameUnderAnyNames( | 
| potential_parents[i].size() >= child.size()) { | 
| result = result || false; | 
| } else { | 
| - size_t domain_diff = FindSubDomainDifference(child, | 
| - potential_parents[i]); | 
| - if (domain_diff == 1 && child[0] != "www") | 
| + size_t domain_diff = FindSubDomainDifference(child, potential_parents[i]); | 
| + if (domain_diff == 1 && child[0] != "www") | 
| result = result || true; | 
| } | 
| } | 
| return result; | 
| } | 
| -bool SSLErrorClassification::AnyNamesUnderName( | 
| - const std::vector<Tokens>& potential_children, | 
| - const Tokens& parent) const { | 
| +bool AnyNamesUnderName(const std::vector<HostnameTokens>& potential_children, | 
| + const HostnameTokens& parent) { | 
| bool result = false; | 
| // Need to account for all the possible domains given in the SSL certificate. | 
| for (size_t i = 0; i < potential_children.size(); ++i) { | 
| @@ -328,20 +306,21 @@ bool SSLErrorClassification::AnyNamesUnderName( | 
| potential_children[i].size() <= parent.size()) { | 
| result = result || false; | 
| } else { | 
| - size_t domain_diff = FindSubDomainDifference(potential_children[i], | 
| - parent); | 
| - if (domain_diff == 1 && potential_children[i][0] != "www") | 
| + size_t domain_diff = | 
| + FindSubDomainDifference(potential_children[i], parent); | 
| + if (domain_diff == 1 && potential_children[i][0] != "www") | 
| result = result || true; | 
| } | 
| } | 
| return result; | 
| } | 
| -bool SSLErrorClassification::IsSubDomainOutsideWildcard( | 
| - const Tokens& host_name_tokens) const { | 
| - std::string host_name = request_url_.host(); | 
| +bool IsSubDomainOutsideWildcard(const GURL& request_url, | 
| + const net::X509Certificate& cert) { | 
| + std::string host_name = request_url.host(); | 
| + HostnameTokens host_name_tokens = Tokenize(host_name); | 
| std::vector<std::string> dns_names; | 
| - cert_.GetDNSNames(&dns_names); | 
| + cert.GetDNSNames(&dns_names); | 
| bool result = false; | 
| // This method requires that the host name be longer than the dns name on | 
| @@ -349,27 +328,27 @@ bool SSLErrorClassification::IsSubDomainOutsideWildcard( | 
| for (size_t i = 0; i < dns_names.size(); ++i) { | 
| const std::string& name = dns_names[i]; | 
| if (name.length() < 2 || name.length() >= host_name.length() || | 
| - name.find('\0') != std::string::npos || | 
| - !IsHostNameKnownTLD(name) | 
| - || name[0] != '*' || name[1] != '.') { | 
| + name.find('\0') != std::string::npos || !IsHostNameKnownTLD(name) || | 
| + name[0] != '*' || name[1] != '.') { | 
| continue; | 
| } | 
| // Move past the "*.". | 
| std::string extracted_dns_name = name.substr(2); | 
| - if (FindSubDomainDifference( | 
| - host_name_tokens, Tokenize(extracted_dns_name)) == 2) { | 
| + if (FindSubDomainDifference(host_name_tokens, | 
| + Tokenize(extracted_dns_name)) == 2) { | 
| return true; | 
| } | 
| } | 
| return result; | 
| } | 
| -bool SSLErrorClassification::IsCertLikelyFromMultiTenantHosting() const { | 
| - std::string host_name = request_url_.host(); | 
| +bool IsCertLikelyFromMultiTenantHosting(const GURL& request_url, | 
| + const net::X509Certificate& cert) { | 
| + std::string host_name = request_url.host(); | 
| std::vector<std::string> dns_names; | 
| std::vector<std::string> dns_names_domain; | 
| - cert_.GetDNSNames(&dns_names); | 
| + cert.GetDNSNames(&dns_names); | 
| size_t dns_names_size = dns_names.size(); | 
| // If there is only 1 DNS name then it is definitely not a shared certificate. | 
| @@ -380,8 +359,7 @@ bool SSLErrorClassification::IsCertLikelyFromMultiTenantHosting() const { | 
| // the same or not. | 
| for (size_t i = 0; i < dns_names_size; ++i) { | 
| dns_names_domain.push_back( | 
| - net::registry_controlled_domains:: | 
| - GetDomainAndRegistry( | 
| + net::registry_controlled_domains::GetDomainAndRegistry( | 
| dns_names[i], | 
| net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)); | 
| } | 
| @@ -413,10 +391,11 @@ bool SSLErrorClassification::IsCertLikelyFromMultiTenantHosting() const { | 
| return true; | 
| } | 
| -bool SSLErrorClassification::IsCertLikelyFromSameDomain() const { | 
| - std::string host_name = request_url_.host(); | 
| +bool IsCertLikelyFromSameDomain(const GURL& request_url, | 
| + const net::X509Certificate& cert) { | 
| + std::string host_name = request_url.host(); | 
| std::vector<std::string> dns_names; | 
| - cert_.GetDNSNames(&dns_names); | 
| + cert.GetDNSNames(&dns_names); | 
| dns_names.push_back(host_name); | 
| std::vector<std::string> dns_names_domain; | 
| @@ -436,9 +415,9 @@ bool SSLErrorClassification::IsCertLikelyFromSameDomain() const { | 
| host_name_domain) != dns_names_domain.end() - 1; | 
| } | 
| -// static | 
| -bool SSLErrorClassification::IsHostnameNonUniqueOrDotless( | 
| - const std::string& hostname) { | 
| +bool IsHostnameNonUniqueOrDotless(const std::string& hostname) { | 
| return net::IsHostnameNonUnique(hostname) || | 
| hostname.find('.') == std::string::npos; | 
| } | 
| + | 
| +} // namespace ssl_errors |