Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(146)

Side by Side Diff: net/quic/crypto/strike_register.h

Issue 2193073003: Move shared files in net/quic/ into net/quic/core/ (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: io_thread_unittest.cc Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/quic/crypto/scoped_evp_aead_ctx.cc ('k') | net/quic/crypto/strike_register.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2013 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_QUIC_CRYPTO_STRIKE_REGISTER_H_
6 #define NET_QUIC_CRYPTO_STRIKE_REGISTER_H_
7
8 #include <stdint.h>
9
10 #include <memory>
11 #include <set>
12 #include <utility>
13 #include <vector>
14
15 #include "base/macros.h"
16 #include "net/base/net_export.h"
17
18 namespace net {
19
20 // InsertStatus enum values cannot be changed, they need to be stable.
21 enum InsertStatus {
22 NONCE_OK = 0,
23 // The default error value for nonce verification failures from strike
24 // register (covers old strike registers and unknown failures).
25 NONCE_UNKNOWN_FAILURE = 1,
26 // Decrypted nonce had incorrect length.
27 NONCE_INVALID_FAILURE = 2,
28 // Nonce is not unique.
29 NONCE_NOT_UNIQUE_FAILURE = 3,
30 // Nonce's orbit is invalid or incorrect.
31 NONCE_INVALID_ORBIT_FAILURE = 4,
32 // Nonce's timestamp is not in the strike register's valid time range.
33 NONCE_INVALID_TIME_FAILURE = 5,
34 // Strike register's RPC call timed out, nonce couldn't be verified.
35 STRIKE_REGISTER_TIMEOUT = 6,
36 // Strike register is down, nonce couldn't be verified.
37 STRIKE_REGISTER_FAILURE = 7,
38 };
39
40 // A StrikeRegister is critbit tree which stores a set of observed nonces.
41 // We use a critbit tree because:
42 // 1) It's immune to algorithmic complexity attacks. If we had used a hash
43 // tree, an attacker could send us a series of values which stretch out one
44 // of the hash chains, causing us to do much more work than normal.
45 // 2) We can write it to use a fixed block of memory: avoiding fragmentation
46 // issues and so forth. (We might be able to do that with the STL
47 // algorithms and a custom allocator, but I don't want to go there.)
48 // 3) It's simple (compared to balanced binary trees) and doesn't involve
49 // bouncing nearly as many cache lines around.
50 // 4) It allows us to query for the oldest element in log(n) time.
51 //
52 // This code is based on djb's public domain critbit tree from qhasm.
53 //
54 // A critbit tree has external and internal nodes. External nodes are just the
55 // nonce values (which are stored with internal times, see below, and without
56 // the orbit values included). Internal nodes contain the bit number at which
57 // the tree is branching and exactly two children. The critical bit is stored
58 // as a byte number and a byte (|otherbits|) which has all the bits set
59 // /except/ the one in question.
60 //
61 // Internal nodes have exactly two children: an internal node with only a
62 // single child would be useless.
63 //
64 // The branching bit number (considering the MSB to be the 1st bit) is
65 // monotonically increasing as you go down the tree.
66 //
67 // There are two distinct time representations used. External times are those
68 // which are exposed to the users of this class. They are expected to be a
69 // count of the number of seconds since the UNIX epoch. Internal times are a
70 // count of the number of seconds since a point in time a couple of years
71 // before the creation time given to the constructor. (See
72 // |ExternalTimeToInternal|) This avoids having to worry about overflow since
73 // we assume that no process will run for 130 years.
74 class NET_EXPORT_PRIVATE StrikeRegister {
75 public:
76 enum StartupType {
77 // DENY_REQUESTS_AT_STARTUP is the typical mode for a strike register.
78 // Because servers can crash and the strike-register memory-based, the
79 // state of the strike-register may be lost at any time. Thus the previous
80 // instance of the server may have accepted an nonce with time
81 // now+window_secs, which was forgotten in the crash. Therefore
82 // DENY_REQUESTS_AT_STARTUP causes the strike-register to reject all
83 // requests timestampped before window_secs + the creation time (the
84 // quiescent period).
85 DENY_REQUESTS_AT_STARTUP,
86 // NO_STARTUP_PERIOD_NEEDED indicates that no quiescent period is required.
87 // This may be because the strike-register is using an orbit randomly
88 // generated at startup and therefore nonces accepted by the previous
89 // instance of the strike-register are invalid for that reason.
90 NO_STARTUP_PERIOD_NEEDED,
91 };
92
93 // An external node takes 24 bytes as we don't record the orbit.
94 static const uint32_t kExternalNodeSize;
95
96 // We address the nodes by their index in the array. This means that 0 is a
97 // valid index. Therefore this is our invalid index. It also has a one bit
98 // in the LSB position because we tend to store indexes shifted up 8 bits
99 // and this distinguishes kNil from (kExternalFlag | 0) << 8.
100 static const uint32_t kNil;
101
102 // Our pointers from internal nodes can either point to an internal or
103 // external node. We flag the 24th bit to mark a pointer as external.
104 static const uint32_t kExternalFlag;
105
106 // Allows early validation before a strike register is created.
107 static void ValidateStrikeRegisterConfig(unsigned max_entries);
108
109 // Construct a new set which can hold, at most, |max_entries| (which must be
110 // less than 2**23). See the comments around StartupType about initial
111 // behaviour. Otherwise, all nonces that are outside +/- |window_secs| from
112 // the current time will be rejected. Additionally, all nonces that have an
113 // orbit value other than |orbit| will be rejected.
114 //
115 // (Note that this code is independent of the actual units of time used, but
116 // you should use seconds.)
117 StrikeRegister(unsigned max_entries,
118 uint32_t current_time_external,
119 uint32_t window_secs,
120 const uint8_t orbit[8],
121 StartupType startup);
122
123 ~StrikeRegister();
124
125 void Reset();
126
127 // |Insert| queries to see if |nonce| is
128 // a) for the wrong orbit
129 // b) before the current horizon
130 // c) outside of the valid time window
131 // d) already in the set of observed nonces
132 // and returns the failure reason if any of these are true. It is also free to
133 // return failure reason for other reasons as it's always safe to reject an
134 // nonce.
135 //
136 // nonces are:
137 // 4 bytes of timestamp (UNIX epoch seconds)
138 // 8 bytes of orbit value (a cluster id)
139 // 20 bytes of random data
140 //
141 // Otherwise, it inserts |nonce| into the observed set and returns NONCE_OK.
142 InsertStatus Insert(const uint8_t nonce[32], uint32_t current_time);
143
144 // orbit returns a pointer to the 8-byte orbit value for this
145 // strike-register.
146 const uint8_t* orbit() const;
147
148 // Time window for which the strike register has complete information.
149 uint32_t GetCurrentValidWindowSecs(uint32_t current_time_external) const;
150
151 // This is a debugging aid which checks the tree for sanity.
152 void Validate();
153
154 private:
155 class InternalNode;
156
157 // TimeFromBytes returns a big-endian uint32_t from |d|.
158 static uint32_t TimeFromBytes(const uint8_t d[4]);
159
160 // Range of internal times for which the strike register has
161 // complete information. A nonce is within the valid range of the
162 // strike register if:
163 // valid_range.first <= nonce_time_internal <= valid_range.second
164 std::pair<uint32_t, uint32_t> GetValidRange(
165 uint32_t current_time_internal) const;
166
167 // ExternalTimeToInternal converts an external time value into an internal
168 // time value using |internal_epoch_|.
169 uint32_t ExternalTimeToInternal(uint32_t external_time) const;
170
171 // BestMatch returns either kNil, or an external node index which could
172 // possibly match |v|.
173 uint32_t BestMatch(const uint8_t v[24]) const;
174
175 // external_node_next_ptr returns the 'next' pointer embedded in external
176 // node |i|. This is used to thread a free list through the external nodes.
177 uint32_t& external_node_next_ptr(unsigned i);
178
179 uint8_t* external_node(unsigned i);
180
181 uint32_t GetFreeExternalNode();
182
183 uint32_t GetFreeInternalNode();
184
185 // DropOldestNode removes the oldest node in the tree and updates |horizon_|
186 // accordingly.
187 void DropOldestNode();
188
189 void FreeExternalNode(uint32_t index);
190
191 void FreeInternalNode(uint32_t index);
192
193 void ValidateTree(uint32_t internal_node,
194 int last_bit,
195 const std::vector<std::pair<unsigned, bool>>& bits,
196 const std::set<uint32_t>& free_internal_nodes,
197 const std::set<uint32_t>& free_external_nodes,
198 std::set<uint32_t>* used_internal_nodes,
199 std::set<uint32_t>* used_external_nodes);
200
201 const uint32_t max_entries_;
202 const uint32_t window_secs_;
203 // internal_epoch_ contains the external time value of the start of internal
204 // time.
205 const uint32_t internal_epoch_;
206 uint8_t orbit_[8];
207 // The strike register will reject nonces with internal times < |horizon_| .
208 uint32_t horizon_;
209
210 uint32_t internal_node_free_head_;
211 uint32_t external_node_free_head_;
212 uint32_t internal_node_head_;
213 // internal_nodes_ can't be a scoped_ptr because the type isn't defined in
214 // this header.
215 InternalNode* internal_nodes_;
216 std::unique_ptr<uint8_t[]> external_nodes_;
217
218 DISALLOW_COPY_AND_ASSIGN(StrikeRegister);
219 };
220
221 } // namespace net
222
223 #endif // NET_QUIC_CRYPTO_STRIKE_REGISTER_H_
OLDNEW
« no previous file with comments | « net/quic/crypto/scoped_evp_aead_ctx.cc ('k') | net/quic/crypto/strike_register.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698