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

Side by Side Diff: net/quic/crypto/strike_register_test.cc

Issue 15937012: Land Recent QUIC changes. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Small bug fixes Created 7 years, 6 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/quic/crypto/strike_register.h" 5 #include "net/quic/crypto/strike_register.h"
6 6
7 #include <set> 7 #include <set>
8 #include <string> 8 #include <string>
9 9
10 #include "base/basictypes.h" 10 #include "base/basictypes.h"
11 #include "testing/gtest/include/gtest/gtest.h" 11 #include "testing/gtest/include/gtest/gtest.h"
12 12
13 namespace { 13 namespace {
14 14
15 using net::StrikeRegister; 15 using net::StrikeRegister;
16 using std::set; 16 using std::set;
17 using std::string; 17 using std::string;
18 18
19 const uint8 kOrbit[8] = { 1, 2, 3, 4, 5, 6, 7, 8 }; 19 const uint8 kOrbit[8] = { 1, 2, 3, 4, 5, 6, 7, 8 };
20 20
21 void 21 void
22 NonceSetTimeAndOrbit(uint8 nonce[32], unsigned time, const uint8 orbit[8]) { 22 NonceSetTimeAndOrbit(uint8 nonce[32], unsigned time, const uint8 orbit[8]) {
wtc 2013/06/03 17:24:00 It is a little surprising that a function named "s
ramant (doing other things) 2013/06/14 03:26:16 Fixed in CL: https://codereview.chromium.org/17040
23 nonce[0] = time >> 24; 23 nonce[0] = time >> 24;
24 nonce[1] = time >> 16; 24 nonce[1] = time >> 16;
25 nonce[2] = time >> 8; 25 nonce[2] = time >> 8;
26 nonce[3] = time; 26 nonce[3] = time;
27 memcpy(nonce + 4, orbit, 8); 27 memcpy(nonce + 4, orbit, 8);
28 memset(nonce + 12, 0, 20);
28 } 29 }
29 30
30 TEST(StrikeRegisterTest, SimpleHorizon) { 31 TEST(StrikeRegisterTest, SimpleHorizon) {
31 // The set must reject values created on or before its own creation time. 32 // The set must reject values created on or before its own creation time.
32 StrikeRegister set(10 /* max size */, 1000 /* current time */, 33 StrikeRegister set(10 /* max size */, 1000 /* current time */,
33 100 /* window secs */, kOrbit); 34 100 /* window secs */, kOrbit,
35 StrikeRegister::DENY_REQUESTS_AT_STARTUP);
34 uint8 nonce[32]; 36 uint8 nonce[32];
35 NonceSetTimeAndOrbit(nonce, 999, kOrbit); 37 NonceSetTimeAndOrbit(nonce, 999, kOrbit);
36 ASSERT_FALSE(set.Insert(nonce, 1000)); 38 ASSERT_FALSE(set.Insert(nonce, 1000));
37 NonceSetTimeAndOrbit(nonce, 1000, kOrbit); 39 NonceSetTimeAndOrbit(nonce, 1000, kOrbit);
38 ASSERT_FALSE(set.Insert(nonce, 1000)); 40 ASSERT_FALSE(set.Insert(nonce, 1000));
39 } 41 }
40 42
43 TEST(StrikeRegisterTest, NoStartupMode) {
44 // Check that a strike register works immediately if NO_STARTUP_PERIOD_NEEDED
45 // is specified.
46 StrikeRegister set(10 /* max size */, 0 /* current time */,
47 100 /* window secs */, kOrbit,
48 StrikeRegister::NO_STARTUP_PERIOD_NEEDED);
49 uint8 nonce[32];
50 NonceSetTimeAndOrbit(nonce, 0, kOrbit);
51 ASSERT_TRUE(set.Insert(nonce, 0));
52 ASSERT_FALSE(set.Insert(nonce, 0));
53 }
54
41 TEST(StrikeRegisterTest, WindowFuture) { 55 TEST(StrikeRegisterTest, WindowFuture) {
42 // The set must reject values outside the window. 56 // The set must reject values outside the window.
43 StrikeRegister set(10 /* max size */, 1000 /* current time */, 57 StrikeRegister set(10 /* max size */, 1000 /* current time */,
44 100 /* window secs */, kOrbit); 58 100 /* window secs */, kOrbit,
59 StrikeRegister::DENY_REQUESTS_AT_STARTUP);
45 uint8 nonce[32]; 60 uint8 nonce[32];
46 NonceSetTimeAndOrbit(nonce, 1101, kOrbit); 61 NonceSetTimeAndOrbit(nonce, 1101, kOrbit);
47 ASSERT_FALSE(set.Insert(nonce, 1000)); 62 ASSERT_FALSE(set.Insert(nonce, 1000));
48 NonceSetTimeAndOrbit(nonce, 999, kOrbit); 63 NonceSetTimeAndOrbit(nonce, 999, kOrbit);
49 ASSERT_FALSE(set.Insert(nonce, 1100)); 64 ASSERT_FALSE(set.Insert(nonce, 1100));
50 } 65 }
51 66
52 TEST(StrikeRegisterTest, BadOrbit) { 67 TEST(StrikeRegisterTest, BadOrbit) {
53 // The set must reject values with the wrong orbit 68 // The set must reject values with the wrong orbit
54 StrikeRegister set(10 /* max size */, 1000 /* current time */, 69 StrikeRegister set(10 /* max size */, 1000 /* current time */,
55 100 /* window secs */, kOrbit); 70 100 /* window secs */, kOrbit,
71 StrikeRegister::DENY_REQUESTS_AT_STARTUP);
56 uint8 nonce[32]; 72 uint8 nonce[32];
57 static const uint8 kBadOrbit[8] = { 0, 0, 0, 0, 1, 1, 1, 1 }; 73 static const uint8 kBadOrbit[8] = { 0, 0, 0, 0, 1, 1, 1, 1 };
58 NonceSetTimeAndOrbit(nonce, 1101, kBadOrbit); 74 NonceSetTimeAndOrbit(nonce, 1101, kBadOrbit);
59 ASSERT_FALSE(set.Insert(nonce, 1100)); 75 ASSERT_FALSE(set.Insert(nonce, 1100));
60 } 76 }
61 77
62 TEST(StrikeRegisterTest, OneValue) { 78 TEST(StrikeRegisterTest, OneValue) {
63 StrikeRegister set(10 /* max size */, 1000 /* current time */, 79 StrikeRegister set(10 /* max size */, 1000 /* current time */,
64 100 /* window secs */, kOrbit); 80 100 /* window secs */, kOrbit,
81 StrikeRegister::DENY_REQUESTS_AT_STARTUP);
65 uint8 nonce[32]; 82 uint8 nonce[32];
66 NonceSetTimeAndOrbit(nonce, 1101, kOrbit); 83 NonceSetTimeAndOrbit(nonce, 1101, kOrbit);
67 ASSERT_TRUE(set.Insert(nonce, 1100)); 84 ASSERT_TRUE(set.Insert(nonce, 1100));
68 } 85 }
69 86
70 TEST(StrikeRegisterTest, RejectDuplicate) { 87 TEST(StrikeRegisterTest, RejectDuplicate) {
71 // The set must reject values with the wrong orbit 88 // The set must reject values with the wrong orbit
72 StrikeRegister set(10 /* max size */, 1000 /* current time */, 89 StrikeRegister set(10 /* max size */, 1000 /* current time */,
73 100 /* window secs */, kOrbit); 90 100 /* window secs */, kOrbit,
91 StrikeRegister::DENY_REQUESTS_AT_STARTUP);
74 uint8 nonce[32]; 92 uint8 nonce[32];
75 memset(nonce, 0, sizeof(nonce)); 93 memset(nonce, 0, sizeof(nonce));
76 NonceSetTimeAndOrbit(nonce, 1101, kOrbit); 94 NonceSetTimeAndOrbit(nonce, 1101, kOrbit);
77 ASSERT_TRUE(set.Insert(nonce, 1100)); 95 ASSERT_TRUE(set.Insert(nonce, 1100));
78 ASSERT_FALSE(set.Insert(nonce, 1100)); 96 ASSERT_FALSE(set.Insert(nonce, 1100));
79 } 97 }
80 98
81 TEST(StrikeRegisterTest, HorizonUpdating) { 99 TEST(StrikeRegisterTest, HorizonUpdating) {
82 StrikeRegister set(5 /* max size */, 1000 /* current time */, 100 StrikeRegister set(5 /* max size */, 1000 /* current time */,
83 100 /* window secs */, kOrbit); 101 100 /* window secs */, kOrbit,
102 StrikeRegister::DENY_REQUESTS_AT_STARTUP);
84 uint8 nonce[6][32]; 103 uint8 nonce[6][32];
85 for (unsigned i = 0; i < 5; i++) { 104 for (unsigned i = 0; i < 5; i++) {
86 NonceSetTimeAndOrbit(nonce[i], 1101, kOrbit); 105 NonceSetTimeAndOrbit(nonce[i], 1101, kOrbit);
87 memset(nonce[i] + 12, 0, 20); 106 memset(nonce[i] + 12, 0, 20);
88 nonce[i][31] = i; 107 nonce[i][31] = i;
89 ASSERT_TRUE(set.Insert(nonce[i], 1100)); 108 ASSERT_TRUE(set.Insert(nonce[i], 1100));
90 } 109 }
91 110
92 // This should push the oldest value out and force the horizon to be updated. 111 // This should push the oldest value out and force the horizon to be updated.
93 NonceSetTimeAndOrbit(nonce[5], 1102, kOrbit); 112 NonceSetTimeAndOrbit(nonce[5], 1102, kOrbit);
94 memset(nonce[5] + 12, 0, 20); 113 memset(nonce[5] + 12, 0, 20);
95 ASSERT_TRUE(set.Insert(nonce[5], 1100)); 114 ASSERT_TRUE(set.Insert(nonce[5], 1100));
96 115
97 // This should be behind the horizon now: 116 // This should be behind the horizon now:
98 NonceSetTimeAndOrbit(nonce[5], 1101, kOrbit); 117 NonceSetTimeAndOrbit(nonce[5], 1101, kOrbit);
99 memset(nonce[5] + 12, 0, 20); 118 memset(nonce[5] + 12, 0, 20);
100 nonce[5][31] = 10; 119 nonce[5][31] = 10;
101 ASSERT_FALSE(set.Insert(nonce[5], 1100)); 120 ASSERT_FALSE(set.Insert(nonce[5], 1100));
102 } 121 }
103 122
104 TEST(StrikeRegisterTest, InsertMany) { 123 TEST(StrikeRegisterTest, InsertMany) {
105 StrikeRegister set(5000 /* max size */, 1000 /* current time */, 124 StrikeRegister set(5000 /* max size */, 1000 /* current time */,
106 500 /* window secs */, kOrbit); 125 500 /* window secs */, kOrbit,
126 StrikeRegister::DENY_REQUESTS_AT_STARTUP);
107 127
108 uint8 nonce[32]; 128 uint8 nonce[32];
109 NonceSetTimeAndOrbit(nonce, 1101, kOrbit); 129 NonceSetTimeAndOrbit(nonce, 1101, kOrbit);
110 for (unsigned i = 0; i < 100000; i++) { 130 for (unsigned i = 0; i < 100000; i++) {
111 NonceSetTimeAndOrbit(nonce, 1101 + i/500, kOrbit); 131 NonceSetTimeAndOrbit(nonce, 1101 + i/500, kOrbit);
112 memcpy(nonce + 12, &i, sizeof(i)); 132 memcpy(nonce + 12, &i, sizeof(i));
113 set.Insert(nonce, 1100); 133 set.Insert(nonce, 1100);
114 } 134 }
115 } 135 }
116 136
117 137
118 // For the following test we create a slow, but simple, version of a 138 // For the following test we create a slow, but simple, version of a
119 // StrikeRegister. The behaviour of this object is much easier to understand 139 // StrikeRegister. The behaviour of this object is much easier to understand
120 // than the fully fledged version. We then create a test to show, empirically, 140 // than the fully fledged version. We then create a test to show, empirically,
121 // that the two objects have identical behaviour. 141 // that the two objects have identical behaviour.
122 142
123 // A SlowStrikeRegister has the same public interface as a StrikeRegister, but 143 // A SlowStrikeRegister has the same public interface as a StrikeRegister, but
124 // is much slower. Hopefully it is also more obviously correct and we can 144 // is much slower. Hopefully it is also more obviously correct and we can
125 // empirically test that their behaviours are identical. 145 // empirically test that their behaviours are identical.
126 class SlowStrikeRegister { 146 class SlowStrikeRegister {
127 public: 147 public:
128 SlowStrikeRegister(unsigned max_entries, uint32 current_time, 148 SlowStrikeRegister(unsigned max_entries, uint32 current_time,
129 uint32 window_secs, const uint8 orbit[8]) 149 uint32 window_secs, const uint8 orbit[8])
130 : max_entries_(max_entries), 150 : max_entries_(max_entries),
131 window_secs_(window_secs), 151 window_secs_(window_secs),
132 horizon_(current_time + window_secs) { 152 creation_time_(current_time),
153 horizon_(ExternalTimeToInternal(current_time + window_secs)) {
133 memcpy(orbit_, orbit, sizeof(orbit_)); 154 memcpy(orbit_, orbit, sizeof(orbit_));
134 } 155 }
135 156
136 bool Insert(const uint8 nonce_bytes[32], const uint32 current_time) { 157 bool Insert(const uint8 nonce_bytes[32], const uint32 current_time_external) {
137 // Same overflow and underflow check as the real StrikeRegister. 158 const uint32 current_time = ExternalTimeToInternal(current_time_external);
138 if (current_time < window_secs_ ||
139 current_time + window_secs_ < current_time) {
140 nonces_.clear();
141 horizon_ = current_time;
142 return false;
143 }
144 159
145 // Check to see if the orbit is correct. 160 // Check to see if the orbit is correct.
146 if (memcmp(nonce_bytes + 4, orbit_, sizeof(orbit_))) { 161 if (memcmp(nonce_bytes + 4, orbit_, sizeof(orbit_))) {
147 return false; 162 return false;
148 } 163 }
149 const uint32 nonce_time = TimeFromBytes(nonce_bytes); 164 const uint32 nonce_time =
165 ExternalTimeToInternal(TimeFromBytes(nonce_bytes));
150 // We have dropped one or more nonces with a time value of |horizon_|, so 166 // We have dropped one or more nonces with a time value of |horizon_|, so
151 // we have to reject anything with a timestamp less than or equal to that. 167 // we have to reject anything with a timestamp less than or equal to that.
152 if (nonce_time <= horizon_) { 168 if (nonce_time <= horizon_) {
153 return false; 169 return false;
154 } 170 }
155 171
156 // Check that the timestamp is in the current window. 172 // Check that the timestamp is in the current window.
157 if (nonce_time < (current_time - window_secs_) || 173 if ((current_time > window_secs_ &&
174 nonce_time < (current_time - window_secs_)) ||
158 nonce_time > (current_time + window_secs_)) { 175 nonce_time > (current_time + window_secs_)) {
159 return false; 176 return false;
160 } 177 }
161 178
162 const string nonce(reinterpret_cast<const char*>(nonce_bytes), 32); 179 string nonce;
180 nonce.reserve(32);
181 nonce +=
182 string(reinterpret_cast<const char*>(&nonce_time), sizeof(nonce_time));
183 nonce +=
184 string(reinterpret_cast<const char*>(nonce_bytes) + sizeof(nonce_time),
185 32 - sizeof(nonce_time));
163 186
164 set<string>::const_iterator it = nonces_.find(nonce); 187 set<string>::const_iterator it = nonces_.find(nonce);
165 if (it != nonces_.end()) { 188 if (it != nonces_.end()) {
166 return false; 189 return false;
167 } 190 }
168 191
169 if (nonces_.size() == max_entries_) { 192 if (nonces_.size() == max_entries_) {
170 DropOldestEntry(); 193 DropOldestEntry();
171 } 194 }
172 195
173 nonces_.insert(nonce); 196 nonces_.insert(nonce);
174 return true; 197 return true;
175 } 198 }
176 199
177 private: 200 private:
178 // TimeFromBytes returns a big-endian uint32 from |d|. 201 // TimeFromBytes returns a big-endian uint32 from |d|.
179 static uint32 TimeFromBytes(const uint8 d[4]) { 202 static uint32 TimeFromBytes(const uint8 d[4]) {
180 return static_cast<uint32>(d[0]) << 24 | 203 return static_cast<uint32>(d[0]) << 24 |
181 static_cast<uint32>(d[1]) << 16 | 204 static_cast<uint32>(d[1]) << 16 |
182 static_cast<uint32>(d[2]) << 8 | 205 static_cast<uint32>(d[2]) << 8 |
183 static_cast<uint32>(d[3]); 206 static_cast<uint32>(d[3]);
184 } 207 }
185 208
209 uint32 ExternalTimeToInternal(uint32 external_time) {
210 static const uint32 kCreationTimeFromInternalEpoch = 63115200.0;
211 uint32 internal_epoch = 0;
212 if (creation_time_ > kCreationTimeFromInternalEpoch) {
213 internal_epoch = creation_time_ - kCreationTimeFromInternalEpoch;
214 }
215
216 return external_time - internal_epoch;
217 }
218
186 void DropOldestEntry() { 219 void DropOldestEntry() {
187 set<string>::iterator oldest = nonces_.begin(), it; 220 set<string>::iterator oldest = nonces_.begin(), it;
188 uint32 oldest_time = 221 uint32 oldest_time =
189 TimeFromBytes(reinterpret_cast<const uint8*>(oldest->data())); 222 TimeFromBytes(reinterpret_cast<const uint8*>(oldest->data()));
190 223
191 for (it = oldest; it != nonces_.end(); it++) { 224 for (it = oldest; it != nonces_.end(); it++) {
192 uint32 t = TimeFromBytes(reinterpret_cast<const uint8*>(it->data())); 225 uint32 t = TimeFromBytes(reinterpret_cast<const uint8*>(it->data()));
193 if (t < oldest_time || 226 if (t < oldest_time ||
194 (t == oldest_time && memcmp(it->data(), oldest->data(), 32) < 0)) { 227 (t == oldest_time && memcmp(it->data(), oldest->data(), 32) < 0)) {
195 oldest_time = t; 228 oldest_time = t;
196 oldest = it; 229 oldest = it;
197 } 230 }
198 } 231 }
199 232
200 nonces_.erase(oldest); 233 nonces_.erase(oldest);
201 horizon_ = oldest_time; 234 horizon_ = oldest_time;
202 } 235 }
203 236
204 const unsigned max_entries_; 237 const unsigned max_entries_;
205 const unsigned window_secs_; 238 const unsigned window_secs_;
239 const uint32 creation_time_;
206 uint8 orbit_[8]; 240 uint8 orbit_[8];
207 uint32 horizon_; 241 uint32 horizon_;
208 242
209 set<string> nonces_; 243 set<string> nonces_;
210 }; 244 };
211 245
212 TEST(StrikeRegisterStressTest, Stress) { 246 TEST(StrikeRegisterStressTest, Stress) {
213 // Fixed seed gives reproducibility for this test. 247 // Fixed seed gives reproducibility for this test.
214 srand(42); 248 srand(42);
215 unsigned max_entries = 64; 249 unsigned max_entries = 64;
216 uint32 current_time = 10000, window = 200; 250 uint32 current_time = 10000, window = 200;
217 scoped_ptr<StrikeRegister> s1( 251 scoped_ptr<StrikeRegister> s1(
218 new StrikeRegister(max_entries, current_time, window, kOrbit)); 252 new StrikeRegister(max_entries, current_time, window, kOrbit,
253 StrikeRegister::DENY_REQUESTS_AT_STARTUP));
219 scoped_ptr<SlowStrikeRegister> s2( 254 scoped_ptr<SlowStrikeRegister> s2(
220 new SlowStrikeRegister(max_entries, current_time, window, kOrbit)); 255 new SlowStrikeRegister(max_entries, current_time, window, kOrbit));
221 uint64 i; 256 uint64 i;
222 257
223 // When making changes it's worth removing the limit on this test and running 258 // When making changes it's worth removing the limit on this test and running
224 // it for a while. For the initial development an opt binary was left running 259 // it for a while. For the initial development an opt binary was left running
225 // for 10 minutes. 260 // for 10 minutes.
226 const uint64 kMaxIterations = 10000; 261 const uint64 kMaxIterations = 10000;
227 for (i = 0; i < kMaxIterations; i++) { 262 for (i = 0; i < kMaxIterations; i++) {
228 if (rand() % 1000 == 0) { 263 if (rand() % 1000 == 0) {
229 // 0.1% chance of resetting the sets. 264 // 0.1% chance of resetting the sets.
230 max_entries = rand() % 300 + 2; 265 max_entries = rand() % 300 + 2;
231 current_time = rand() % 10000; 266 current_time = rand() % 10000;
232 window = rand() % 500; 267 window = rand() % 500;
233 s1.reset(new StrikeRegister(max_entries, current_time, window, kOrbit)); 268 s1.reset(new StrikeRegister(max_entries, current_time, window, kOrbit,
269 StrikeRegister::DENY_REQUESTS_AT_STARTUP));
234 s2.reset( 270 s2.reset(
235 new SlowStrikeRegister(max_entries, current_time, window, kOrbit)); 271 new SlowStrikeRegister(max_entries, current_time, window, kOrbit));
236 } 272 }
237 273
238 int32 time_delta = rand() % (window * 4); 274 int32 time_delta = rand() % (window * 4);
239 time_delta -= window * 2; 275 time_delta -= window * 2;
240 const uint32 time = current_time + time_delta; 276 const uint32 time = current_time + time_delta;
241 if (time_delta < 0 && time > current_time) { 277 if (time_delta < 0 && time > current_time) {
242 continue; // overflow 278 continue; // overflow
243 } 279 }
(...skipping 18 matching lines...) Expand all
262 s1->Validate(); 298 s1->Validate();
263 } 299 }
264 } 300 }
265 301
266 if (i != kMaxIterations) { 302 if (i != kMaxIterations) {
267 FAIL() << "Failed after " << i << " iterations"; 303 FAIL() << "Failed after " << i << " iterations";
268 } 304 }
269 } 305 }
270 306
271 } // anonymous namespace 307 } // anonymous namespace
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698