• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef NET_BASE_TRANSPORT_SECURITY_STATE_H_
6 #define NET_BASE_TRANSPORT_SECURITY_STATE_H_
7 #pragma once
8 
9 #include <map>
10 #include <string>
11 #include <vector>
12 
13 #include "base/basictypes.h"
14 #include "base/gtest_prod_util.h"
15 #include "base/memory/ref_counted.h"
16 #include "base/time.h"
17 #include "net/base/x509_cert_types.h"
18 
19 namespace net {
20 
21 // TransportSecurityState
22 //
23 // Tracks which hosts have enabled *-Transport-Security. This object manages
24 // the in-memory store. A separate object must register itself with this object
25 // in order to persist the state to disk.
26 class TransportSecurityState :
27     public base::RefCountedThreadSafe<TransportSecurityState> {
28  public:
29   TransportSecurityState();
30 
31   // A DomainState is the information that we persist about a given domain.
32   struct DomainState {
33     enum Mode {
34       // Strict mode implies:
35       //   * We generate internal redirects from HTTP -> HTTPS.
36       //   * Certificate issues are fatal.
37       MODE_STRICT = 0,
38       // Opportunistic mode implies:
39       //   * We'll request HTTP URLs over HTTPS
40       //   * Certificate issues are ignored.
41       MODE_OPPORTUNISTIC = 1,
42       // SPDY_ONLY (aka X-Bodge-Transport-Security) is a hopefully temporary
43       // measure. It implies:
44       //   * We'll request HTTP URLs over HTTPS iff we have SPDY support.
45       //   * Certificate issues are fatal.
46       MODE_SPDY_ONLY = 2,
47       // None means there is no HSTS for this domain.
48       MODE_NONE = 3,
49     };
50 
51     DomainState();
52     ~DomainState();
53 
54     // IsChainOfPublicKeysPermitted takes a set of public key hashes and
55     // returns true if:
56     //   1) |public_key_hashes| is empty, i.e. no public keys have been pinned.
57     //   2) |hashes| and |public_key_hashes| are not disjoint.
58     bool IsChainOfPublicKeysPermitted(
59         const std::vector<SHA1Fingerprint>& hashes);
60 
61     Mode mode;
62     base::Time created;  // when this host entry was first created
63     base::Time expiry;  // the absolute time (UTC) when this record expires
64     bool include_subdomains;  // subdomains included?
65     std::vector<SHA1Fingerprint> public_key_hashes;  // optional; permitted keys
66 
67     // The follow members are not valid when stored in |enabled_hosts_|.
68     bool preloaded;  // is this a preloaded entry?
69     std::string domain;  // the domain which matched
70   };
71 
72   // Enable TransportSecurity for |host|.
73   void EnableHost(const std::string& host, const DomainState& state);
74 
75   // Delete any entry for |host|. If |host| doesn't have an exact entry then no
76   // action is taken. Returns true iff an entry was deleted.
77   bool DeleteHost(const std::string& host);
78 
79   // Returns true if |host| has TransportSecurity enabled, in the context of
80   // |sni_available|. In that case, *result is filled out.
81   bool IsEnabledForHost(DomainState* result,
82                         const std::string& host,
83                         bool sni_available);
84 
85   // Deletes all records created since a given time.
86   void DeleteSince(const base::Time& time);
87 
88   // Returns |true| if |value| parses as a valid *-Transport-Security
89   // header value.  The values of max-age and and includeSubDomains are
90   // returned in |max_age| and |include_subdomains|, respectively.  The out
91   // parameters are not modified if the function returns |false|.
92   static bool ParseHeader(const std::string& value,
93                           int* max_age,
94                           bool* include_subdomains);
95 
96   class Delegate {
97    public:
98     // This function may not block and may be called with internal locks held.
99     // Thus it must not reenter the TransportSecurityState object.
100     virtual void StateIsDirty(TransportSecurityState* state) = 0;
101 
102    protected:
~Delegate()103     virtual ~Delegate() {}
104   };
105 
106   void SetDelegate(Delegate*);
107 
108   bool Serialise(std::string* output);
109   // Existing non-preloaded entries are cleared and repopulated from the
110   // passed JSON string.
111   bool LoadEntries(const std::string& state, bool* dirty);
112 
113   // The maximum number of seconds for which we'll cache an HSTS request.
114   static const long int kMaxHSTSAgeSecs;
115 
116  private:
117   friend class base::RefCountedThreadSafe<TransportSecurityState>;
118   FRIEND_TEST_ALL_PREFIXES(TransportSecurityStateTest, IsPreloaded);
119 
120   ~TransportSecurityState();
121 
122   // If we have a callback configured, call it to let our serialiser know that
123   // our state is dirty.
124   void DirtyNotify();
125 
126   static std::string CanonicalizeHost(const std::string& host);
127   static bool IsPreloadedSTS(const std::string& canonicalized_host,
128                              bool sni_available,
129                              DomainState* out);
130   static bool Deserialise(const std::string& state,
131                           bool* dirty,
132                           std::map<std::string, DomainState>* out);
133 
134   // The set of hosts that have enabled TransportSecurity. The keys here
135   // are SHA256(DNSForm(domain)) where DNSForm converts from dotted form
136   // ('www.google.com') to the form used in DNS: "\x03www\x06google\x03com"
137   std::map<std::string, DomainState> enabled_hosts_;
138 
139   // Our delegate who gets notified when we are dirtied, or NULL.
140   Delegate* delegate_;
141 
142   DISALLOW_COPY_AND_ASSIGN(TransportSecurityState);
143 };
144 
145 }  // namespace net
146 
147 #endif  // NET_BASE_TRANSPORT_SECURITY_STATE_H_
148