summaryrefslogtreecommitdiffstats
path: root/net/base/transport_security_state.h
blob: a3f1462618e3825706e1a9637b1b1c805e7968fd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef NET_BASE_TRANSPORT_SECURITY_STATE_H_
#define NET_BASE_TRANSPORT_SECURITY_STATE_H_
#pragma once

#include <map>
#include <string>
#include <vector>

#include "base/basictypes.h"
#include "base/gtest_prod_util.h"
#include "base/memory/ref_counted.h"
#include "base/time.h"
#include "net/base/net_api.h"
#include "net/base/x509_cert_types.h"

namespace net {

// TransportSecurityState
//
// Tracks which hosts have enabled *-Transport-Security. This object manages
// the in-memory store. A separate object must register itself with this object
// in order to persist the state to disk.
class NET_API TransportSecurityState :
    public base::RefCountedThreadSafe<TransportSecurityState> {
 public:
  // If non-empty, |hsts_hosts| is a JSON-formatted string to treat as if it
  // were a built-in entry (same format as persisted metadata in the
  // TransportSecurityState file).
  explicit TransportSecurityState(const std::string& hsts_hosts);

  // A DomainState is the information that we persist about a given domain.
  struct NET_API DomainState {
    enum Mode {
      // Strict mode implies:
      //   * We generate internal redirects from HTTP -> HTTPS.
      //   * Certificate issues are fatal.
      MODE_STRICT = 0,
      // Opportunistic mode implies:
      //   * We'll request HTTP URLs over HTTPS
      //   * Certificate issues are ignored.
      MODE_OPPORTUNISTIC = 1,
      // SPDY_ONLY (aka X-Bodge-Transport-Security) is a hopefully temporary
      // measure. It implies:
      //   * We'll request HTTP URLs over HTTPS iff we have SPDY support.
      //   * Certificate issues are fatal.
      MODE_SPDY_ONLY = 2,
      // None means there is no HSTS for this domain.
      MODE_NONE = 3,
    };

    DomainState();
    ~DomainState();

    // IsChainOfPublicKeysPermitted takes a set of public key hashes and
    // returns true if:
    //   1) |public_key_hashes| is empty, i.e. no public keys have been pinned.
    //   2) |hashes| and |public_key_hashes| are not disjoint.
    bool IsChainOfPublicKeysPermitted(
        const std::vector<SHA1Fingerprint>& hashes);

    Mode mode;
    base::Time created;  // when this host entry was first created
    base::Time expiry;  // the absolute time (UTC) when this record expires
    bool include_subdomains;  // subdomains included?
    std::vector<SHA1Fingerprint> public_key_hashes;  // optional; permitted keys

    // The follow members are not valid when stored in |enabled_hosts_|.
    bool preloaded;  // is this a preloaded entry?
    std::string domain;  // the domain which matched
  };

  // Enable TransportSecurity for |host|.
  void EnableHost(const std::string& host, const DomainState& state);

  // Delete any entry for |host|. If |host| doesn't have an exact entry then no
  // action is taken. Returns true iff an entry was deleted.
  bool DeleteHost(const std::string& host);

  // Returns true if |host| has TransportSecurity enabled, in the context of
  // |sni_available|. In that case, *result is filled out.
  // Note that *result is always overwritten on every call.
  bool IsEnabledForHost(DomainState* result,
                        const std::string& host,
                        bool sni_available);

  // Returns true if |host| has any SSL certificate pinning, in the context of
  // |sni_available|. In that case, *result is filled out.
  // Note that *result is always overwritten on every call.
  bool HasPinsForHost(DomainState* result,
                      const std::string& host,
                      bool sni_available);

  // Returns true if |host| has any HSTS metadata, in the context of
  // |sni_available|. (This include cert-pin-only metadata).
  // In that case, *result is filled out.
  // Note that *result is always overwritten on every call.
  bool HasMetadata(DomainState* result,
                   const std::string& host,
                   bool sni_available);

  // Deletes all records created since a given time.
  void DeleteSince(const base::Time& time);

  // Returns |true| if |value| parses as a valid *-Transport-Security
  // header value.  The values of max-age and and includeSubDomains are
  // returned in |max_age| and |include_subdomains|, respectively.  The out
  // parameters are not modified if the function returns |false|.
  static bool ParseHeader(const std::string& value,
                          int* max_age,
                          bool* include_subdomains);

  class Delegate {
   public:
    // This function may not block and may be called with internal locks held.
    // Thus it must not reenter the TransportSecurityState object.
    virtual void StateIsDirty(TransportSecurityState* state) = 0;

   protected:
    virtual ~Delegate() {}
  };

  void SetDelegate(Delegate*);

  bool Serialise(std::string* output);
  // Existing non-preloaded entries are cleared and repopulated from the
  // passed JSON string.
  bool LoadEntries(const std::string& state, bool* dirty);

  // The maximum number of seconds for which we'll cache an HSTS request.
  static const long int kMaxHSTSAgeSecs;

 private:
  friend class base::RefCountedThreadSafe<TransportSecurityState>;
  FRIEND_TEST_ALL_PREFIXES(TransportSecurityStateTest, IsPreloaded);

  ~TransportSecurityState();

  // If we have a callback configured, call it to let our serialiser know that
  // our state is dirty.
  void DirtyNotify();
  bool IsPreloadedSTS(const std::string& canonicalized_host,
                      bool sni_available,
                      DomainState* out);

  static std::string CanonicalizeHost(const std::string& host);
  static bool Deserialise(const std::string& state,
                          bool* dirty,
                          std::map<std::string, DomainState>* out);

  // The set of hosts that have enabled TransportSecurity. The keys here
  // are SHA256(DNSForm(domain)) where DNSForm converts from dotted form
  // ('www.google.com') to the form used in DNS: "\x03www\x06google\x03com"
  std::map<std::string, DomainState> enabled_hosts_;

  // These hosts are extra rules to treat as built-in, passed in the
  // constructor (typically originating from the command line).
  std::map<std::string, DomainState> forced_hosts_;

  // Our delegate who gets notified when we are dirtied, or NULL.
  Delegate* delegate_;

  DISALLOW_COPY_AND_ASSIGN(TransportSecurityState);
};

}  // namespace net

#endif  // NET_BASE_TRANSPORT_SECURITY_STATE_H_