1116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Copyright 2014 The Chromium Authors. All rights reserved. 2116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Use of this source code is governed by a BSD-style license that can be 3116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// found in the LICENSE file. 4116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 5116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#ifndef CHROME_BROWSER_SSL_SSL_ERROR_CLASSIFICATION_H_ 6116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#define CHROME_BROWSER_SSL_SSL_ERROR_CLASSIFICATION_H_ 7116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 85f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include <string> 95f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include <vector> 105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 11116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/time/time.h" 121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/public/browser/notification_observer.h" 131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/public/browser/notification_registrar.h" 14116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "net/cert/x509_certificate.h" 155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "url/gurl.h" 16116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace content { 181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciclass WebContents; 191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// This class classifies characteristics of SSL errors, including information 221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// about captive portal detection. 231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// 241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// This class should only be used on the UI thread because its 251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// implementation uses captive_portal::CaptivePortalService which can only be 261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// accessed on the UI thread. 271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciclass SSLErrorClassification : public content::NotificationObserver { 28116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch public: 291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci SSLErrorClassification(content::WebContents* web_contents, 301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const base::Time& current_time, 315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const GURL& url, 321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci int cert_error, 33116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const net::X509Certificate& cert); 341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci virtual ~SSLErrorClassification(); 35116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Returns true if the system time is in the past. 375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) static bool IsUserClockInThePast(const base::Time& time_now); 385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Returns true if the system time is too far in the future or the user is 405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // using a version of Chrome which is more than 1 year old. 415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) static bool IsUserClockInTheFuture(const base::Time& time_now); 42116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Returns true if the Windows platform is likely to not have SHA-256 support. 441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // On other platforms, returns false always. 451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci static bool MaybeWindowsLacksSHA256Support(); 46116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // A function which calculates the severity score when the ssl error is 481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // |CERT_DATE_INVALID|. The calculated score is between 0.0 and 1.0, higher 491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // being more severe, indicating how severe the certificate's 501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // date invalid error is. 511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci void InvalidDateSeverityScore(); 52116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // A function which calculates the severity score when the ssl error is 541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // |CERT_COMMON_NAME_INVALID|. The calculated score is between 0.0 and 1.0, 551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // higher being more severe, indicating how severe the certificate's common 561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // name invalid error is. 571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci void InvalidCommonNameSeverityScore(); 585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci void RecordUMAStatistics(bool overridable) const; 601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci void RecordCaptivePortalUMAStatistics(bool overridable) const; 61116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch base::TimeDelta TimePassedSinceExpiry() const; 62116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 63116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch private: 645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) FRIEND_TEST_ALL_PREFIXES(SSLErrorClassificationTest, TestDateInvalidScore); 655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) FRIEND_TEST_ALL_PREFIXES(SSLErrorClassificationTest, TestNameMismatch); 665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) FRIEND_TEST_ALL_PREFIXES(SSLErrorClassificationTest, 675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) TestHostNameHasKnownTLD); 685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) typedef std::vector<std::string> Tokens; 705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Returns true if the hostname has a known Top Level Domain. 725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) static bool IsHostNameKnownTLD(const std::string& host_name); 735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Returns true if the site's hostname differs from one of the DNS 755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // names in the certificate (CN or SANs) only by the presence or 765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // absence of the single-label prefix "www". E.g.: 775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // 785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // www.example.com ~ example.com -> true 795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // example.com ~ www.example.com -> true 805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // www.food.example.com ~ example.com -> false 815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // mail.example.com ~ example.com -> false 825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) bool IsWWWSubDomainMatch() const; 835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Returns true if |child| is a subdomain of any of the |potential_parents|. 855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) bool NameUnderAnyNames(const Tokens& child, 865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const std::vector<Tokens>& potential_parents) const; 875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Returns true if any of the |potential_children| is a subdomain of the 895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // |parent|. The inverse case should be treated carefully as this is most 905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // likely a MITM attack. We don't want foo.appspot.com to be able to MITM for 915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // appspot.com. 925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) bool AnyNamesUnderName(const std::vector<Tokens>& potential_children, 935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const Tokens& parent) const; 945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Returns true if |hostname| is too broad for the scope of a wildcard 965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // certificate. E.g.: 975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // 985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // a.b.example.com ~ *.example.com --> true 995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // b.example.com ~ *.example.com --> false 1005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) bool IsSubDomainOutsideWildcard(const Tokens& hostname) const; 101116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 1026e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // Returns true if the certificate is a shared certificate. Note - This 1036e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // function should be used with caution (only for UMA histogram) as an 1046e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // attacker could easily get a certificate with more than 5 names in the SAN 1056e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // fields. 1066e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) bool IsCertLikelyFromMultiTenantHosting() const; 1076e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) static std::vector<Tokens> GetTokenizedDNSNames( 1095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const std::vector<std::string>& dns_names); 1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // If |potential_subdomain| is a subdomain of |parent|, returns the 1125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // number of DNS labels by which |potential_subdomain| is under 1135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // |parent|. Otherwise, returns 0. 1145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // 1155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // For example, 1165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // 1175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // FindSubDomainDifference(Tokenize("a.b.example.com"), 1185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Tokenize("example.com")) 1195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // --> 2. 1205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) size_t FindSubDomainDifference(const Tokens& potential_subdomain, 1215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const Tokens& parent) const; 1225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) static Tokens Tokenize(const std::string& name); 1245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci float CalculateScoreTimePassedSinceExpiry() const; 1261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci float CalculateScoreEnvironments() const; 1271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // content::NotificationObserver: 1291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci virtual void Observe( 1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci int type, 1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const content::NotificationSource& source, 1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci const content::NotificationDetails& details) OVERRIDE; 1331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci content::WebContents* web_contents_; 135116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // This stores the current time. 136116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch base::Time current_time_; 1375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) const GURL& request_url_; 1381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci int cert_error_; 139116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // This stores the certificate. 140116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const net::X509Certificate& cert_; 1411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Is captive portal detection enabled? 1421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci bool captive_portal_detection_enabled_; 1431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Did the probe complete before the interstitial was closed? 1441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci bool captive_portal_probe_completed_; 1451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Did the captive portal probe receive an error or get a non-HTTP response? 1461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci bool captive_portal_no_response_; 1471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Was a captive portal detected? 1481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci bool captive_portal_detected_; 1491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci content::NotificationRegistrar registrar_; 151116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}; 152116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 153116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#endif // CHROME_BROWSER_SSL_SSL_ERROR_CLASSIFICATION_H_ 154