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