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
19namespace 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.
26class 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:
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