1 // Copyright (c) 2012 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.
5 #ifndef NET_HTTP_TRANSPORT_SECURITY_STATE_H_
6 #define NET_HTTP_TRANSPORT_SECURITY_STATE_H_
13 #include "base/basictypes.h"
14 #include "base/gtest_prod_util.h"
15 #include "base/threading/non_thread_safe.h"
16 #include "base/time/time.h"
17 #include "net/base/net_export.h"
18 #include "net/cert/x509_cert_types.h"
19 #include "net/cert/x509_certificate.h"
25 // Tracks which hosts have enabled strict transport security and/or public
28 // This object manages the in-memory store. Register a Delegate with
29 // |SetDelegate| to persist the state to disk.
31 // HTTP strict transport security (HSTS) is defined in
32 // http://tools.ietf.org/html/ietf-websec-strict-transport-sec, and
33 // HTTP-based dynamic public key pinning (HPKP) is defined in
34 // http://tools.ietf.org/html/ietf-websec-key-pinning.
35 class NET_EXPORT TransportSecurityState
36 : NON_EXPORTED_BASE(public base::NonThreadSafe
) {
38 class NET_EXPORT Delegate
{
40 // This function may not block and may be called with internal locks held.
41 // Thus it must not reenter the TransportSecurityState object.
42 virtual void StateIsDirty(TransportSecurityState
* state
) = 0;
45 virtual ~Delegate() {}
48 TransportSecurityState();
49 ~TransportSecurityState();
51 // A DomainState describes the transport security state (required upgrade
52 // to HTTPS, and/or any public key pins).
53 class NET_EXPORT DomainState
{
56 // These numbers must match those in hsts_view.js, function modeToString.
64 // Takes a set of SubjectPublicKeyInfo |hashes| and returns true if:
65 // 1) |bad_static_spki_hashes| does not intersect |hashes|; AND
66 // 2) Both |static_spki_hashes| and |dynamic_spki_hashes| are empty
67 // or at least one of them intersects |hashes|.
69 // |{dynamic,static}_spki_hashes| contain trustworthy public key hashes,
70 // any one of which is sufficient to validate the certificate chain in
71 // question. The public keys could be of a root CA, intermediate CA, or
72 // leaf certificate, depending on the security vs. disaster recovery
73 // tradeoff selected. (Pinning only to leaf certifiates increases
74 // security because you no longer trust any CAs, but it hampers disaster
75 // recovery because you can't just get a new certificate signed by the
78 // |bad_static_spki_hashes| contains public keys that we don't want to
80 bool CheckPublicKeyPins(const HashValueVector
& hashes
,
81 std::string
* failure_log
) const;
83 // Returns true if any of the HashValueVectors |static_spki_hashes|,
84 // |bad_static_spki_hashes|, or |dynamic_spki_hashes| contains any
86 bool HasPublicKeyPins() const;
88 // ShouldUpgradeToSSL returns true iff, given the |mode| of this
89 // DomainState, HTTP requests should be internally redirected to HTTPS
90 // (also if the "ws" WebSocket request should be upgraded to "wss")
91 bool ShouldUpgradeToSSL() const;
93 // ShouldSSLErrorsBeFatal returns true iff HTTPS errors should cause
94 // hard-fail behavior (e.g. if HSTS is set for the domain)
95 bool ShouldSSLErrorsBeFatal() const;
97 UpgradeMode upgrade_mode
;
99 // The absolute time (UTC) when the |upgrade_mode| was observed.
101 // TODO(palmer): Perhaps static entries should have an "observed" time.
102 base::Time sts_observed
;
104 // The absolute time (UTC) when the |dynamic_spki_hashes| (and other
105 // |dynamic_*| state) were observed.
107 // TODO(palmer): Perhaps static entries should have an "observed" time.
108 base::Time pkp_observed
;
110 // The absolute time (UTC) when the |upgrade_mode|, if set to
111 // UPGRADE_ALWAYS, downgrades to UPGRADE_NEVER.
112 base::Time upgrade_expiry
;
114 // Are subdomains subject to this DomainState, for the purposes of
115 // upgrading to HTTPS?
116 bool sts_include_subdomains
;
118 // Are subdomains subject to this DomainState, for the purposes of
120 bool pkp_include_subdomains
;
122 // Optional; hashes of static pinned SubjectPublicKeyInfos. Unless both
123 // are empty, at least one of |static_spki_hashes| and
124 // |dynamic_spki_hashes| MUST intersect with the set of SPKIs in the TLS
125 // server's certificate chain.
127 // |dynamic_spki_hashes| take precedence over |static_spki_hashes|.
128 // That is, |IsChainOfPublicKeysPermitted| first checks dynamic pins and
129 // then checks static pins.
130 HashValueVector static_spki_hashes
;
132 // Optional; hashes of dynamically pinned SubjectPublicKeyInfos.
133 HashValueVector dynamic_spki_hashes
;
135 // The absolute time (UTC) when the |dynamic_spki_hashes| expire.
136 base::Time dynamic_spki_hashes_expiry
;
138 // Optional; hashes of static known-bad SubjectPublicKeyInfos which
139 // MUST NOT intersect with the set of SPKIs in the TLS server's
140 // certificate chain.
141 HashValueVector bad_static_spki_hashes
;
143 // The following members are not valid when stored in |enabled_hosts_|:
145 // The domain which matched during a search for this DomainState entry.
146 // Updated by |GetDomainState|, |GetDynamicDomainState|, and
147 // |GetStaticDomainState|.
151 class NET_EXPORT Iterator
{
153 explicit Iterator(const TransportSecurityState
& state
);
156 bool HasNext() const { return iterator_
!= end_
; }
157 void Advance() { ++iterator_
; }
158 const std::string
& hostname() const { return iterator_
->first
; }
159 const DomainState
& domain_state() const { return iterator_
->second
; }
162 std::map
<std::string
, DomainState
>::const_iterator iterator_
;
163 std::map
<std::string
, DomainState
>::const_iterator end_
;
166 // Assign a |Delegate| for persisting the transport security state. If
167 // |NULL|, state will not be persisted. The caller retains
168 // ownership of |delegate|.
169 // Note: This is only used for serializing/deserializing the
170 // TransportSecurityState.
171 void SetDelegate(Delegate
* delegate
);
173 // Clears all dynamic data (e.g. HSTS and HPKP data).
175 // Does NOT persist changes using the Delegate, as this function is only
176 // used to clear any dynamic data prior to re-loading it from a file.
177 // Note: This is only used for serializing/deserializing the
178 // TransportSecurityState.
179 void ClearDynamicData();
181 // Inserts |state| into |enabled_hosts_| under the key |hashed_host|.
182 // |hashed_host| is already in the internal representation
183 // HashHost(CanonicalizeHost(host)).
184 // Note: This is only used for serializing/deserializing the
185 // TransportSecurityState.
186 void AddOrUpdateEnabledHosts(const std::string
& hashed_host
,
187 const DomainState
& state
);
189 // Deletes all dynamic data (e.g. HSTS or HPKP data) created since a given
192 // If any entries are deleted, the new state will be persisted through
193 // the Delegate (if any).
194 void DeleteAllDynamicDataSince(const base::Time
& time
);
196 // Deletes any dynamic data stored for |host| (e.g. HSTS or HPKP data).
197 // If |host| doesn't have an exact entry then no action is taken. Does
198 // not delete static (i.e. preloaded) data. Returns true iff an entry
201 // If an entry is deleted, the new state will be persisted through
202 // the Delegate (if any).
203 bool DeleteDynamicDataForHost(const std::string
& host
);
205 // Returns true and updates |*result| iff there is a DomainState for
208 // If |sni_enabled| is true, searches the static pins defined for
209 // SNI-using hosts as well as the rest of the pins.
211 // If |host| matches both an exact entry and is a subdomain of another
212 // entry, the exact match determines the return value.
214 // Note that this method is not const because it opportunistically removes
215 // entries that have expired.
216 bool GetDomainState(const std::string
& host
,
218 DomainState
* result
);
220 // Processes an HSTS header value from the host, adding entries to
221 // dynamic state if necessary.
222 bool AddHSTSHeader(const std::string
& host
, const std::string
& value
);
224 // Processes an HPKP header value from the host, adding entries to
225 // dynamic state if necessary. ssl_info is used to check that
226 // the specified pins overlap with the certificate chain.
227 bool AddHPKPHeader(const std::string
& host
, const std::string
& value
,
228 const SSLInfo
& ssl_info
);
230 // Adds explicitly-specified data as if it was processed from an
231 // HSTS header (used for net-internals and unit tests).
232 bool AddHSTS(const std::string
& host
, const base::Time
& expiry
,
233 bool include_subdomains
);
235 // Adds explicitly-specified data as if it was processed from an
236 // HPKP header (used for net-internals and unit tests).
237 bool AddHPKP(const std::string
& host
, const base::Time
& expiry
,
238 bool include_subdomains
, const HashValueVector
& hashes
);
240 // Returns true iff we have any static public key pins for the |host| and
241 // iff its set of required pins is the set we expect for Google
244 // If |sni_enabled| is true, searches the static pins defined for
245 // SNI-using hosts as well as the rest of the pins.
247 // If |host| matches both an exact entry and is a subdomain of another
248 // entry, the exact match determines the return value.
249 static bool IsGooglePinnedProperty(const std::string
& host
,
252 // The maximum number of seconds for which we'll cache an HSTS request.
253 static const long int kMaxHSTSAgeSecs
;
255 // Send an UMA report on pin validation failure, if the host is in a
256 // statically-defined list of domains.
258 // TODO(palmer): This doesn't really belong here, and should be moved into
259 // the exactly one call site. This requires unifying |struct HSTSPreload|
260 // (an implementation detail of this class) with a more generic
261 // representation of first-class DomainStates, and exposing the preloads
262 // to the caller with |GetStaticDomainState|.
263 static void ReportUMAOnPinFailure(const std::string
& host
);
265 // IsBuildTimely returns true if the current build is new enough ensure that
266 // built in security information (i.e. HSTS preloading and pinning
267 // information) is timely.
268 static bool IsBuildTimely();
271 friend class TransportSecurityStateTest
;
272 FRIEND_TEST_ALL_PREFIXES(HttpSecurityHeadersTest
,
273 UpdateDynamicPKPOnly
);
275 typedef std::map
<std::string
, DomainState
> DomainStateMap
;
277 // If a Delegate is present, notify it that the internal state has
281 // Enable TransportSecurity for |host|. |state| supercedes any previous
282 // state for the |host|, including static entries.
284 // The new state for |host| is persisted using the Delegate (if any).
285 void EnableHost(const std::string
& host
, const DomainState
& state
);
287 // Converts |hostname| from dotted form ("www.google.com") to the form
288 // used in DNS: "\x03www\x06google\x03com", lowercases that, and returns
290 static std::string
CanonicalizeHost(const std::string
& hostname
);
292 // Returns true and updates |*result| iff there is a static DomainState for
295 // |GetStaticDomainState| is identical to |GetDomainState| except that it
296 // searches only the statically-defined transport security state, ignoring
297 // all dynamically-added DomainStates.
299 // If |sni_enabled| is true, searches the static pins defined for
300 // SNI-using hosts as well as the rest of the pins.
302 // If |host| matches both an exact entry and is a subdomain of another
303 // entry, the exact match determines the return value.
305 // Note that this method is not const because it opportunistically removes
306 // entries that have expired.
307 bool GetStaticDomainState(const std::string
& host
,
309 DomainState
* result
);
311 // Returns true and updates |*result| iff there is a dynamic DomainState for
314 // |GetDynamicDomainState| is identical to |GetDomainState| except that it
315 // searches only the dynamically-added transport security state, ignoring
316 // all statically-defined DomainStates.
318 // If |host| matches both an exact entry and is a subdomain of another
319 // entry, the exact match determines the return value.
321 // Note that this method is not const because it opportunistically removes
322 // entries that have expired.
323 bool GetDynamicDomainState(const std::string
& host
, DomainState
* result
);
325 // The set of hosts that have enabled TransportSecurity.
326 DomainStateMap enabled_hosts_
;
330 DISALLOW_COPY_AND_ASSIGN(TransportSecurityState
);
335 #endif // NET_HTTP_TRANSPORT_SECURITY_STATE_H_