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_
15 #include "base/gtest_prod_util.h"
16 #include "base/threading/non_thread_safe.h"
17 #include "base/time/time.h"
18 #include "net/base/net_export.h"
19 #include "net/cert/x509_cert_types.h"
20 #include "net/cert/x509_certificate.h"
30 // Tracks which hosts have enabled strict transport security and/or public
33 // This object manages the in-memory store. Register a Delegate with
34 // |SetDelegate| to persist the state to disk.
36 // HTTP strict transport security (HSTS) is defined in
37 // http://tools.ietf.org/html/ietf-websec-strict-transport-sec, and
38 // HTTP-based dynamic public key pinning (HPKP) is defined in
39 // http://tools.ietf.org/html/ietf-websec-key-pinning.
40 class NET_EXPORT TransportSecurityState
41 : NON_EXPORTED_BASE(public base::NonThreadSafe
) {
43 class NET_EXPORT Delegate
{
45 // This function may not block and may be called with internal locks held.
46 // Thus it must not reenter the TransportSecurityState object.
47 virtual void StateIsDirty(TransportSecurityState
* state
) = 0;
50 virtual ~Delegate() {}
53 // A STSState describes the strict transport security state (required
55 class NET_EXPORT STSState
{
58 // These numbers must match those in hsts_view.js, function modeToString.
66 // The absolute time (UTC) when the |upgrade_mode| (and other state) was
68 base::Time last_observed
;
70 // The absolute time (UTC) when |upgrade_mode| (and other state)
74 UpgradeMode upgrade_mode
;
76 // Are subdomains subject to this policy state?
77 bool include_subdomains
;
79 // The domain which matched during a search for this STSState entry.
80 // Updated by |GetDynamicSTSState| and |GetStaticDomainState|.
83 // ShouldUpgradeToSSL returns true iff HTTP requests should be internally
84 // redirected to HTTPS (also if WS should be upgraded to WSS).
85 bool ShouldUpgradeToSSL() const;
87 // ShouldSSLErrorsBeFatal returns true iff HTTPS errors should cause
88 // hard-fail behavior (e.g. if HSTS is set for the domain).
89 bool ShouldSSLErrorsBeFatal() const;
92 class NET_EXPORT STSStateIterator
{
94 explicit STSStateIterator(const TransportSecurityState
& state
);
97 bool HasNext() const { return iterator_
!= end_
; }
98 void Advance() { ++iterator_
; }
99 const std::string
& hostname() const { return iterator_
->first
; }
100 const STSState
& domain_state() const { return iterator_
->second
; }
103 std::map
<std::string
, STSState
>::const_iterator iterator_
;
104 std::map
<std::string
, STSState
>::const_iterator end_
;
107 // A PKPState describes the public key pinning state.
108 class NET_EXPORT PKPState
{
113 // The absolute time (UTC) when the |spki_hashes| (and other state) were
115 base::Time last_observed
;
117 // The absolute time (UTC) when the |spki_hashes| expire.
120 // Optional; hashes of pinned SubjectPublicKeyInfos.
121 HashValueVector spki_hashes
;
123 // Optional; hashes of static known-bad SubjectPublicKeyInfos which MUST
124 // NOT intersect with the set of SPKIs in the TLS server's certificate
126 HashValueVector bad_spki_hashes
;
128 // Are subdomains subject to this policy state?
129 bool include_subdomains
;
131 // The domain which matched during a search for this DomainState entry.
132 // Updated by |GetDynamicPKPState| and |GetStaticDomainState|.
135 // An optional URI indicating where reports should be sent when this
136 // pin is violated, or empty when omitted.
139 // Takes a set of SubjectPublicKeyInfo |hashes| and returns true if:
140 // 1) |bad_static_spki_hashes| does not intersect |hashes|; AND
141 // 2) Both |static_spki_hashes| and |dynamic_spki_hashes| are empty
142 // or at least one of them intersects |hashes|.
144 // |{dynamic,static}_spki_hashes| contain trustworthy public key hashes,
145 // any one of which is sufficient to validate the certificate chain in
146 // question. The public keys could be of a root CA, intermediate CA, or
147 // leaf certificate, depending on the security vs. disaster recovery
148 // tradeoff selected. (Pinning only to leaf certifiates increases
149 // security because you no longer trust any CAs, but it hampers disaster
150 // recovery because you can't just get a new certificate signed by the
153 // |bad_static_spki_hashes| contains public keys that we don't want to
155 bool CheckPublicKeyPins(const HashValueVector
& hashes
,
156 std::string
* failure_log
) const;
158 // Returns true if any of the HashValueVectors |static_spki_hashes|,
159 // |bad_static_spki_hashes|, or |dynamic_spki_hashes| contains any
161 bool HasPublicKeyPins() const;
163 // ShouldSSLErrorsBeFatal returns true iff HTTPS errors should cause
164 // hard-fail behavior (e.g. if HSTS is set for the domain).
165 bool ShouldSSLErrorsBeFatal() const;
168 class NET_EXPORT PKPStateIterator
{
170 explicit PKPStateIterator(const TransportSecurityState
& state
);
173 bool HasNext() const { return iterator_
!= end_
; }
174 void Advance() { ++iterator_
; }
175 const std::string
& hostname() const { return iterator_
->first
; }
176 const PKPState
& domain_state() const { return iterator_
->second
; }
179 std::map
<std::string
, PKPState
>::const_iterator iterator_
;
180 std::map
<std::string
, PKPState
>::const_iterator end_
;
183 // An interface for asynchronously sending HPKP violation reports.
184 class NET_EXPORT ReportSender
{
186 // Sends the given serialized |report| to |report_uri|.
187 virtual void Send(const GURL
& report_uri
, const std::string
& report
) = 0;
190 virtual ~ReportSender() {}
193 // Indicates whether or not a public key pin check should send a
194 // report if a violation is detected.
195 enum PublicKeyPinReportStatus
{ ENABLE_PIN_REPORTS
, DISABLE_PIN_REPORTS
};
197 TransportSecurityState();
198 ~TransportSecurityState();
200 // These functions search for static and dynamic STS and PKP states, and
201 // invoke the functions of the same name on them. These functions are the
202 // primary public interface; direct access to STS and PKP states is best
204 bool ShouldSSLErrorsBeFatal(const std::string
& host
);
205 bool ShouldUpgradeToSSL(const std::string
& host
);
206 bool CheckPublicKeyPins(const HostPortPair
& host_port_pair
,
207 bool is_issued_by_known_root
,
208 const HashValueVector
& hashes
,
209 const X509Certificate
* served_certificate_chain
,
210 const X509Certificate
* validated_certificate_chain
,
211 const PublicKeyPinReportStatus report_status
,
212 std::string
* failure_log
);
213 bool HasPublicKeyPins(const std::string
& host
);
215 // Assign a |Delegate| for persisting the transport security state. If
216 // |NULL|, state will not be persisted. The caller retains
217 // ownership of |delegate|.
218 // Note: This is only used for serializing/deserializing the
219 // TransportSecurityState.
220 void SetDelegate(Delegate
* delegate
);
222 void SetReportSender(ReportSender
* report_sender
);
224 // Clears all dynamic data (e.g. HSTS and HPKP data).
226 // Does NOT persist changes using the Delegate, as this function is only
227 // used to clear any dynamic data prior to re-loading it from a file.
228 // Note: This is only used for serializing/deserializing the
229 // TransportSecurityState.
230 void ClearDynamicData();
232 // Inserts |state| into |enabled_sts_hosts_| under the key |hashed_host|.
233 // |hashed_host| is already in the internal representation.
234 // Note: This is only used for serializing/deserializing the
235 // TransportSecurityState.
236 void AddOrUpdateEnabledSTSHosts(const std::string
& hashed_host
,
237 const STSState
& state
);
239 // Inserts |state| into |enabled_pkp_hosts_| under the key |hashed_host|.
240 // |hashed_host| is already in the internal representation.
241 // Note: This is only used for serializing/deserializing the
242 // TransportSecurityState.
243 void AddOrUpdateEnabledPKPHosts(const std::string
& hashed_host
,
244 const PKPState
& state
);
246 // Deletes all dynamic data (e.g. HSTS or HPKP data) created since a given
249 // If any entries are deleted, the new state will be persisted through
250 // the Delegate (if any).
251 void DeleteAllDynamicDataSince(const base::Time
& time
);
253 // Deletes any dynamic data stored for |host| (e.g. HSTS or HPKP data).
254 // If |host| doesn't have an exact entry then no action is taken. Does
255 // not delete static (i.e. preloaded) data. Returns true iff an entry
258 // If an entry is deleted, the new state will be persisted through
259 // the Delegate (if any).
260 bool DeleteDynamicDataForHost(const std::string
& host
);
262 // Returns true and updates |*sts_result| and |*pkp_result| iff there is a
263 // static (built-in) state for |host|. If multiple entries match |host|,
264 // the most specific match determines the return value.
265 bool GetStaticDomainState(const std::string
& host
,
266 STSState
* sts_result
,
267 PKPState
* pkp_result
) const;
269 // Returns true and updates |*result| iff |host| has HSTS (respectively, HPKP)
270 // state. If multiple HSTS (respectively, HPKP) entries match |host|, the
271 // most specific match determines the HSTS (respectively, HPKP) return value.
273 // Note that these methods are not const because they opportunistically remove
274 // entries that have expired.
275 bool GetDynamicSTSState(const std::string
& host
, STSState
* result
);
276 bool GetDynamicPKPState(const std::string
& host
, PKPState
* result
);
278 // Processes an HSTS header value from the host, adding entries to
279 // dynamic state if necessary.
280 bool AddHSTSHeader(const std::string
& host
, const std::string
& value
);
282 // Processes an HPKP header value from the host, adding entries to
283 // dynamic state if necessary. ssl_info is used to check that
284 // the specified pins overlap with the certificate chain.
285 bool AddHPKPHeader(const std::string
& host
, const std::string
& value
,
286 const SSLInfo
& ssl_info
);
288 // Adds explicitly-specified data as if it was processed from an
289 // HSTS header (used for net-internals and unit tests).
290 void AddHSTS(const std::string
& host
,
291 const base::Time
& expiry
,
292 bool include_subdomains
);
294 // Adds explicitly-specified data as if it was processed from an
295 // HPKP header (used for net-internals and unit tests).
296 void AddHPKP(const std::string
& host
,
297 const base::Time
& expiry
,
298 bool include_subdomains
,
299 const HashValueVector
& hashes
,
300 const GURL
& report_uri
);
302 // Parses |value| as a Public-Key-Pins-Report-Only header value and
303 // sends a HPKP report for |host_port_pair| if |ssl_info| violates the
304 // pin. Returns true if |value| parses and includes a valid
305 // report-uri, and false otherwise.
306 bool ProcessHPKPReportOnlyHeader(const std::string
& value
,
307 const HostPortPair
& host_port_pair
,
308 const SSLInfo
& ssl_info
);
310 // Returns true iff we have any static public key pins for the |host| and
311 // iff its set of required pins is the set we expect for Google
314 // If |host| matches both an exact entry and is a subdomain of another
315 // entry, the exact match determines the return value.
316 static bool IsGooglePinnedProperty(const std::string
& host
);
318 // The maximum number of seconds for which we'll cache an HSTS request.
319 static const long int kMaxHSTSAgeSecs
;
322 friend class TransportSecurityStateTest
;
323 FRIEND_TEST_ALL_PREFIXES(HttpSecurityHeadersTest
, UpdateDynamicPKPOnly
);
324 FRIEND_TEST_ALL_PREFIXES(HttpSecurityHeadersTest
, UpdateDynamicPKPMaxAge0
);
325 FRIEND_TEST_ALL_PREFIXES(HttpSecurityHeadersTest
, NoClobberPins
);
327 typedef std::map
<std::string
, STSState
> STSStateMap
;
328 typedef std::map
<std::string
, PKPState
> PKPStateMap
;
330 // Send an UMA report on pin validation failure, if the host is in a
331 // statically-defined list of domains.
333 // TODO(palmer): This doesn't really belong here, and should be moved into
334 // the exactly one call site. This requires unifying |struct HSTSPreload|
335 // (an implementation detail of this class) with a more generic
336 // representation of first-class DomainStates, and exposing the preloads
337 // to the caller with |GetStaticDomainState|.
338 static void ReportUMAOnPinFailure(const std::string
& host
);
340 // IsBuildTimely returns true if the current build is new enough ensure that
341 // built in security information (i.e. HSTS preloading and pinning
342 // information) is timely.
343 static bool IsBuildTimely();
345 // Helper method for actually checking pins.
346 bool CheckPublicKeyPinsImpl(
347 const HostPortPair
& host_port_pair
,
348 const HashValueVector
& hashes
,
349 const X509Certificate
* served_certificate_chain
,
350 const X509Certificate
* validated_certificate_chain
,
351 const PublicKeyPinReportStatus report_status
,
352 std::string
* failure_log
);
354 // If a Delegate is present, notify it that the internal state has
358 // Adds HSTS state to |host|.
359 void AddHSTSInternal(const std::string
& host
,
360 STSState::UpgradeMode upgrade_mode
,
361 const base::Time
& expiry
,
362 bool include_subdomains
);
364 // Adds HPKP state to |host|.
365 void AddHPKPInternal(const std::string
& host
,
366 const base::Time
& last_observed
,
367 const base::Time
& expiry
,
368 bool include_subdomains
,
369 const HashValueVector
& hashes
,
370 const GURL
& report_uri
);
372 // Enable TransportSecurity for |host|. |state| supercedes any previous
373 // state for the |host|, including static entries.
375 // The new state for |host| is persisted using the Delegate (if any).
376 void EnableSTSHost(const std::string
& host
, const STSState
& state
);
377 void EnablePKPHost(const std::string
& host
, const PKPState
& state
);
379 // The sets of hosts that have enabled TransportSecurity. |domain| will always
380 // be empty for a STSState or PKPState in these maps; the domain
381 // comes from the map keys instead. In addition, |upgrade_mode| in the
382 // STSState is never MODE_DEFAULT and |HasPublicKeyPins| in the PKPState
383 // always returns true.
384 STSStateMap enabled_sts_hosts_
;
385 PKPStateMap enabled_pkp_hosts_
;
389 ReportSender
* report_sender_
;
391 // True if static pins should be used.
392 bool enable_static_pins_
;
394 DISALLOW_COPY_AND_ASSIGN(TransportSecurityState
);
399 #endif // NET_HTTP_TRANSPORT_SECURITY_STATE_H_