OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include <algorithm> | |
6 | |
7 #include "base/base64.h" | |
8 #include "base/sha1.h" | |
9 #include "base/strings/string_piece.h" | |
10 #include "crypto/sha2.h" | |
11 #include "net/base/net_log.h" | |
12 #include "net/base/test_completion_callback.h" | |
13 #include "net/http/http_security_headers.h" | |
14 #include "net/http/http_util.h" | |
15 #include "net/http/transport_security_state.h" | |
16 #include "net/ssl/ssl_info.h" | |
17 #include "testing/gtest/include/gtest/gtest.h" | |
18 | |
19 namespace net { | |
20 | |
21 namespace { | |
22 | |
23 HashValue GetTestHashValue(uint8 label, HashValueTag tag) { | |
24 HashValue hash_value(tag); | |
25 memset(hash_value.data(), label, hash_value.size()); | |
26 return hash_value; | |
27 } | |
28 | |
29 std::string GetTestPinImpl(uint8 label, HashValueTag tag, bool quoted) { | |
30 HashValue hash_value = GetTestHashValue(label, tag); | |
31 std::string base64; | |
32 base::Base64Encode(base::StringPiece( | |
33 reinterpret_cast<char*>(hash_value.data()), hash_value.size()), &base64); | |
34 | |
35 std::string ret; | |
36 switch (hash_value.tag) { | |
37 case HASH_VALUE_SHA1: | |
38 ret = "pin-sha1="; | |
39 break; | |
40 case HASH_VALUE_SHA256: | |
41 ret = "pin-sha256="; | |
42 break; | |
43 default: | |
44 NOTREACHED() << "Unknown HashValueTag " << hash_value.tag; | |
45 return std::string("ERROR"); | |
46 } | |
47 if (quoted) | |
48 ret += '\"'; | |
49 ret += base64; | |
50 if (quoted) | |
51 ret += '\"'; | |
52 return ret; | |
53 } | |
54 | |
55 std::string GetTestPin(uint8 label, HashValueTag tag) { | |
56 return GetTestPinImpl(label, tag, true); | |
57 } | |
58 | |
59 std::string GetTestPinUnquoted(uint8 label, HashValueTag tag) { | |
60 return GetTestPinImpl(label, tag, false); | |
61 } | |
62 | |
63 }; | |
64 | |
65 | |
66 class HttpSecurityHeadersTest : public testing::Test { | |
67 }; | |
68 | |
69 | |
70 TEST_F(HttpSecurityHeadersTest, BogusHeaders) { | |
71 base::TimeDelta max_age; | |
72 bool include_subdomains = false; | |
73 | |
74 EXPECT_FALSE( | |
75 ParseHSTSHeader(std::string(), &max_age, &include_subdomains)); | |
76 EXPECT_FALSE(ParseHSTSHeader(" ", &max_age, &include_subdomains)); | |
77 EXPECT_FALSE(ParseHSTSHeader("abc", &max_age, &include_subdomains)); | |
78 EXPECT_FALSE(ParseHSTSHeader(" abc", &max_age, &include_subdomains)); | |
79 EXPECT_FALSE(ParseHSTSHeader(" abc ", &max_age, &include_subdomains)); | |
80 EXPECT_FALSE(ParseHSTSHeader("max-age", &max_age, &include_subdomains)); | |
81 EXPECT_FALSE(ParseHSTSHeader(" max-age", &max_age, | |
82 &include_subdomains)); | |
83 EXPECT_FALSE(ParseHSTSHeader(" max-age ", &max_age, | |
84 &include_subdomains)); | |
85 EXPECT_FALSE(ParseHSTSHeader("max-age=", &max_age, &include_subdomains)); | |
86 EXPECT_FALSE(ParseHSTSHeader(" max-age=", &max_age, | |
87 &include_subdomains)); | |
88 EXPECT_FALSE(ParseHSTSHeader(" max-age =", &max_age, | |
89 &include_subdomains)); | |
90 EXPECT_FALSE(ParseHSTSHeader(" max-age= ", &max_age, | |
91 &include_subdomains)); | |
92 EXPECT_FALSE(ParseHSTSHeader(" max-age = ", &max_age, | |
93 &include_subdomains)); | |
94 EXPECT_FALSE(ParseHSTSHeader(" max-age = xy", &max_age, | |
95 &include_subdomains)); | |
96 EXPECT_FALSE(ParseHSTSHeader(" max-age = 3488a923", &max_age, | |
97 &include_subdomains)); | |
98 EXPECT_FALSE(ParseHSTSHeader("max-age=3488a923 ", &max_age, | |
99 &include_subdomains)); | |
100 EXPECT_FALSE(ParseHSTSHeader("max-ag=3488923", &max_age, | |
101 &include_subdomains)); | |
102 EXPECT_FALSE(ParseHSTSHeader("max-aged=3488923", &max_age, | |
103 &include_subdomains)); | |
104 EXPECT_FALSE(ParseHSTSHeader("max-age==3488923", &max_age, | |
105 &include_subdomains)); | |
106 EXPECT_FALSE(ParseHSTSHeader("amax-age=3488923", &max_age, | |
107 &include_subdomains)); | |
108 EXPECT_FALSE(ParseHSTSHeader("max-age=-3488923", &max_age, | |
109 &include_subdomains)); | |
110 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923 e", &max_age, | |
111 &include_subdomains)); | |
112 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923 includesubdomain", | |
113 &max_age, &include_subdomains)); | |
114 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923includesubdomains", | |
115 &max_age, &include_subdomains)); | |
116 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923=includesubdomains", | |
117 &max_age, &include_subdomains)); | |
118 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923 includesubdomainx", | |
119 &max_age, &include_subdomains)); | |
120 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923 includesubdomain=", | |
121 &max_age, &include_subdomains)); | |
122 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923 includesubdomain=true", | |
123 &max_age, &include_subdomains)); | |
124 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923 includesubdomainsx", | |
125 &max_age, &include_subdomains)); | |
126 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923 includesubdomains x", | |
127 &max_age, &include_subdomains)); | |
128 EXPECT_FALSE(ParseHSTSHeader("max-age=34889.23 includesubdomains", | |
129 &max_age, &include_subdomains)); | |
130 EXPECT_FALSE(ParseHSTSHeader("max-age=34889 includesubdomains", | |
131 &max_age, &include_subdomains)); | |
132 EXPECT_FALSE(ParseHSTSHeader(";;;; ;;;", | |
133 &max_age, &include_subdomains)); | |
134 EXPECT_FALSE(ParseHSTSHeader(";;;; includeSubDomains;;;", | |
135 &max_age, &include_subdomains)); | |
136 EXPECT_FALSE(ParseHSTSHeader(" includeSubDomains; ", | |
137 &max_age, &include_subdomains)); | |
138 EXPECT_FALSE(ParseHSTSHeader(";", | |
139 &max_age, &include_subdomains)); | |
140 EXPECT_FALSE(ParseHSTSHeader("max-age; ;", | |
141 &max_age, &include_subdomains)); | |
142 | |
143 // Check the out args were not updated by checking the default | |
144 // values for its predictable fields. | |
145 EXPECT_EQ(0, max_age.InSeconds()); | |
146 EXPECT_FALSE(include_subdomains); | |
147 } | |
148 | |
149 static void TestBogusPinsHeaders(HashValueTag tag) { | |
150 base::TimeDelta max_age; | |
151 bool include_subdomains; | |
152 HashValueVector hashes; | |
153 HashValueVector chain_hashes; | |
154 | |
155 // Set some fake "chain" hashes | |
156 chain_hashes.push_back(GetTestHashValue(1, tag)); | |
157 chain_hashes.push_back(GetTestHashValue(2, tag)); | |
158 chain_hashes.push_back(GetTestHashValue(3, tag)); | |
159 | |
160 // The good pin must be in the chain, the backup pin must not be | |
161 std::string good_pin = GetTestPin(2, tag); | |
162 std::string good_pin_unquoted = GetTestPinUnquoted(2, tag); | |
163 std::string backup_pin = GetTestPin(4, tag); | |
164 | |
165 EXPECT_FALSE(ParseHPKPHeader(std::string(), chain_hashes, &max_age, | |
166 &include_subdomains, &hashes)); | |
167 EXPECT_FALSE(ParseHPKPHeader(" ", chain_hashes, &max_age, | |
168 &include_subdomains, &hashes)); | |
169 EXPECT_FALSE(ParseHPKPHeader("abc", chain_hashes, &max_age, | |
170 &include_subdomains, &hashes)); | |
171 EXPECT_FALSE(ParseHPKPHeader(" abc", chain_hashes, &max_age, | |
172 &include_subdomains, &hashes)); | |
173 EXPECT_FALSE(ParseHPKPHeader(" abc ", chain_hashes, &max_age, | |
174 &include_subdomains, &hashes)); | |
175 EXPECT_FALSE(ParseHPKPHeader("max-age", chain_hashes, &max_age, | |
176 &include_subdomains, &hashes)); | |
177 EXPECT_FALSE(ParseHPKPHeader(" max-age", chain_hashes, &max_age, | |
178 &include_subdomains, &hashes)); | |
179 EXPECT_FALSE(ParseHPKPHeader(" max-age ", chain_hashes, &max_age, | |
180 &include_subdomains, &hashes)); | |
181 EXPECT_FALSE(ParseHPKPHeader("max-age=", chain_hashes, &max_age, | |
182 &include_subdomains, &hashes)); | |
183 EXPECT_FALSE(ParseHPKPHeader(" max-age=", chain_hashes, &max_age, | |
184 &include_subdomains, &hashes)); | |
185 EXPECT_FALSE(ParseHPKPHeader(" max-age =", chain_hashes, &max_age, | |
186 &include_subdomains, &hashes)); | |
187 EXPECT_FALSE(ParseHPKPHeader(" max-age= ", chain_hashes, &max_age, | |
188 &include_subdomains, &hashes)); | |
189 EXPECT_FALSE(ParseHPKPHeader(" max-age = ", chain_hashes, | |
190 &max_age, &include_subdomains, &hashes)); | |
191 EXPECT_FALSE(ParseHPKPHeader(" max-age = xy", chain_hashes, | |
192 &max_age, &include_subdomains, &hashes)); | |
193 EXPECT_FALSE(ParseHPKPHeader(" max-age = 3488a923", | |
194 chain_hashes, &max_age, &include_subdomains, | |
195 &hashes)); | |
196 EXPECT_FALSE(ParseHPKPHeader("max-age=3488a923 ", chain_hashes, | |
197 &max_age, &include_subdomains, &hashes)); | |
198 EXPECT_FALSE(ParseHPKPHeader("max-ag=3488923pins=" + good_pin + "," + | |
199 backup_pin, | |
200 chain_hashes, &max_age, &include_subdomains, | |
201 &hashes)); | |
202 EXPECT_FALSE(ParseHPKPHeader("max-aged=3488923" + backup_pin, | |
203 chain_hashes, &max_age, &include_subdomains, | |
204 &hashes)); | |
205 EXPECT_FALSE(ParseHPKPHeader("max-aged=3488923; " + backup_pin, | |
206 chain_hashes, &max_age, &include_subdomains, | |
207 &hashes)); | |
208 EXPECT_FALSE(ParseHPKPHeader("max-aged=3488923; " + backup_pin + ";" + | |
209 backup_pin, | |
210 chain_hashes, &max_age, &include_subdomains, | |
211 &hashes)); | |
212 EXPECT_FALSE(ParseHPKPHeader("max-aged=3488923; " + good_pin + ";" + | |
213 good_pin, | |
214 chain_hashes, &max_age, &include_subdomains, | |
215 &hashes)); | |
216 EXPECT_FALSE(ParseHPKPHeader("max-aged=3488923; " + good_pin, | |
217 chain_hashes, &max_age, &include_subdomains, | |
218 &hashes)); | |
219 EXPECT_FALSE(ParseHPKPHeader("max-age==3488923", chain_hashes, &max_age, | |
220 &include_subdomains, &hashes)); | |
221 EXPECT_FALSE(ParseHPKPHeader("amax-age=3488923", chain_hashes, &max_age, | |
222 &include_subdomains, &hashes)); | |
223 EXPECT_FALSE(ParseHPKPHeader("max-age=-3488923", chain_hashes, &max_age, | |
224 &include_subdomains, &hashes)); | |
225 EXPECT_FALSE(ParseHPKPHeader("max-age=3488923;", chain_hashes, &max_age, | |
226 &include_subdomains, &hashes)); | |
227 EXPECT_FALSE(ParseHPKPHeader("max-age=3488923 e", chain_hashes, | |
228 &max_age, &include_subdomains, &hashes)); | |
229 EXPECT_FALSE(ParseHPKPHeader("max-age=3488923 includesubdomain", | |
230 chain_hashes, &max_age, &include_subdomains, | |
231 &hashes)); | |
232 EXPECT_FALSE(ParseHPKPHeader("max-age=34889.23", chain_hashes, &max_age, | |
233 &include_subdomains, &hashes)); | |
234 EXPECT_FALSE( | |
235 ParseHPKPHeader("max-age=243; " + good_pin_unquoted + ";" + backup_pin, | |
236 chain_hashes, &max_age, &include_subdomains, &hashes)); | |
237 | |
238 // Check the out args were not updated by checking the default | |
239 // values for its predictable fields. | |
240 EXPECT_EQ(0, max_age.InSeconds()); | |
241 EXPECT_EQ(hashes.size(), (size_t)0); | |
242 } | |
243 | |
244 TEST_F(HttpSecurityHeadersTest, ValidSTSHeaders) { | |
245 base::TimeDelta max_age; | |
246 base::TimeDelta expect_max_age; | |
247 bool include_subdomains = false; | |
248 | |
249 EXPECT_TRUE(ParseHSTSHeader("max-age=243", &max_age, | |
250 &include_subdomains)); | |
251 expect_max_age = base::TimeDelta::FromSeconds(243); | |
252 EXPECT_EQ(expect_max_age, max_age); | |
253 EXPECT_FALSE(include_subdomains); | |
254 | |
255 EXPECT_TRUE(ParseHSTSHeader("max-age=3488923;", &max_age, | |
256 &include_subdomains)); | |
257 | |
258 EXPECT_TRUE(ParseHSTSHeader(" Max-agE = 567", &max_age, | |
259 &include_subdomains)); | |
260 expect_max_age = base::TimeDelta::FromSeconds(567); | |
261 EXPECT_EQ(expect_max_age, max_age); | |
262 EXPECT_FALSE(include_subdomains); | |
263 | |
264 EXPECT_TRUE(ParseHSTSHeader(" mAx-aGe = 890 ", &max_age, | |
265 &include_subdomains)); | |
266 expect_max_age = base::TimeDelta::FromSeconds(890); | |
267 EXPECT_EQ(expect_max_age, max_age); | |
268 EXPECT_FALSE(include_subdomains); | |
269 | |
270 EXPECT_TRUE(ParseHSTSHeader("max-age=123;incLudesUbdOmains", &max_age, | |
271 &include_subdomains)); | |
272 expect_max_age = base::TimeDelta::FromSeconds(123); | |
273 EXPECT_EQ(expect_max_age, max_age); | |
274 EXPECT_TRUE(include_subdomains); | |
275 | |
276 EXPECT_TRUE(ParseHSTSHeader("incLudesUbdOmains; max-age=123", &max_age, | |
277 &include_subdomains)); | |
278 expect_max_age = base::TimeDelta::FromSeconds(123); | |
279 EXPECT_EQ(expect_max_age, max_age); | |
280 EXPECT_TRUE(include_subdomains); | |
281 | |
282 EXPECT_TRUE(ParseHSTSHeader(" incLudesUbdOmains; max-age=123", | |
283 &max_age, &include_subdomains)); | |
284 expect_max_age = base::TimeDelta::FromSeconds(123); | |
285 EXPECT_EQ(expect_max_age, max_age); | |
286 EXPECT_TRUE(include_subdomains); | |
287 | |
288 EXPECT_TRUE(ParseHSTSHeader( | |
289 " incLudesUbdOmains; max-age=123; pumpkin=kitten", &max_age, | |
290 &include_subdomains)); | |
291 expect_max_age = base::TimeDelta::FromSeconds(123); | |
292 EXPECT_EQ(expect_max_age, max_age); | |
293 EXPECT_TRUE(include_subdomains); | |
294 | |
295 EXPECT_TRUE(ParseHSTSHeader( | |
296 " pumpkin=894; incLudesUbdOmains; max-age=123 ", &max_age, | |
297 &include_subdomains)); | |
298 expect_max_age = base::TimeDelta::FromSeconds(123); | |
299 EXPECT_EQ(expect_max_age, max_age); | |
300 EXPECT_TRUE(include_subdomains); | |
301 | |
302 EXPECT_TRUE(ParseHSTSHeader( | |
303 " pumpkin; incLudesUbdOmains; max-age=123 ", &max_age, | |
304 &include_subdomains)); | |
305 expect_max_age = base::TimeDelta::FromSeconds(123); | |
306 EXPECT_EQ(expect_max_age, max_age); | |
307 EXPECT_TRUE(include_subdomains); | |
308 | |
309 EXPECT_TRUE(ParseHSTSHeader( | |
310 " pumpkin; incLudesUbdOmains; max-age=\"123\" ", &max_age, | |
311 &include_subdomains)); | |
312 expect_max_age = base::TimeDelta::FromSeconds(123); | |
313 EXPECT_EQ(expect_max_age, max_age); | |
314 EXPECT_TRUE(include_subdomains); | |
315 | |
316 EXPECT_TRUE(ParseHSTSHeader( | |
317 "animal=\"squirrel; distinguished\"; incLudesUbdOmains; max-age=123", | |
318 &max_age, &include_subdomains)); | |
319 expect_max_age = base::TimeDelta::FromSeconds(123); | |
320 EXPECT_EQ(expect_max_age, max_age); | |
321 EXPECT_TRUE(include_subdomains); | |
322 | |
323 EXPECT_TRUE(ParseHSTSHeader("max-age=394082; incLudesUbdOmains", | |
324 &max_age, &include_subdomains)); | |
325 expect_max_age = base::TimeDelta::FromSeconds(394082); | |
326 EXPECT_EQ(expect_max_age, max_age); | |
327 EXPECT_TRUE(include_subdomains); | |
328 | |
329 EXPECT_TRUE(ParseHSTSHeader( | |
330 "max-age=39408299 ;incLudesUbdOmains", &max_age, | |
331 &include_subdomains)); | |
332 expect_max_age = base::TimeDelta::FromSeconds( | |
333 std::min(kMaxHSTSAgeSecs, static_cast<int64>(GG_INT64_C(39408299)))); | |
334 EXPECT_EQ(expect_max_age, max_age); | |
335 EXPECT_TRUE(include_subdomains); | |
336 | |
337 EXPECT_TRUE(ParseHSTSHeader( | |
338 "max-age=394082038 ; incLudesUbdOmains", &max_age, | |
339 &include_subdomains)); | |
340 expect_max_age = base::TimeDelta::FromSeconds( | |
341 std::min(kMaxHSTSAgeSecs, static_cast<int64>(GG_INT64_C(394082038)))); | |
342 EXPECT_EQ(expect_max_age, max_age); | |
343 EXPECT_TRUE(include_subdomains); | |
344 | |
345 EXPECT_TRUE(ParseHSTSHeader( | |
346 "max-age=394082038 ; incLudesUbdOmains;", &max_age, | |
347 &include_subdomains)); | |
348 expect_max_age = base::TimeDelta::FromSeconds( | |
349 std::min(kMaxHSTSAgeSecs, static_cast<int64>(GG_INT64_C(394082038)))); | |
350 EXPECT_EQ(expect_max_age, max_age); | |
351 EXPECT_TRUE(include_subdomains); | |
352 | |
353 EXPECT_TRUE(ParseHSTSHeader( | |
354 ";; max-age=394082038 ; incLudesUbdOmains; ;", &max_age, | |
355 &include_subdomains)); | |
356 expect_max_age = base::TimeDelta::FromSeconds( | |
357 std::min(kMaxHSTSAgeSecs, static_cast<int64>(GG_INT64_C(394082038)))); | |
358 EXPECT_EQ(expect_max_age, max_age); | |
359 EXPECT_TRUE(include_subdomains); | |
360 | |
361 EXPECT_TRUE(ParseHSTSHeader( | |
362 ";; max-age=394082038 ;", &max_age, | |
363 &include_subdomains)); | |
364 expect_max_age = base::TimeDelta::FromSeconds( | |
365 std::min(kMaxHSTSAgeSecs, static_cast<int64>(GG_INT64_C(394082038)))); | |
366 EXPECT_EQ(expect_max_age, max_age); | |
367 EXPECT_FALSE(include_subdomains); | |
368 | |
369 EXPECT_TRUE(ParseHSTSHeader( | |
370 ";; ; ; max-age=394082038;;; includeSubdomains ;; ;", &max_age, | |
371 &include_subdomains)); | |
372 expect_max_age = base::TimeDelta::FromSeconds( | |
373 std::min(kMaxHSTSAgeSecs, static_cast<int64>(GG_INT64_C(394082038)))); | |
374 EXPECT_EQ(expect_max_age, max_age); | |
375 EXPECT_TRUE(include_subdomains); | |
376 | |
377 EXPECT_TRUE(ParseHSTSHeader( | |
378 "incLudesUbdOmains ; max-age=394082038 ;;", &max_age, | |
379 &include_subdomains)); | |
380 expect_max_age = base::TimeDelta::FromSeconds( | |
381 std::min(kMaxHSTSAgeSecs, static_cast<int64>(GG_INT64_C(394082038)))); | |
382 EXPECT_EQ(expect_max_age, max_age); | |
383 EXPECT_TRUE(include_subdomains); | |
384 | |
385 EXPECT_TRUE(ParseHSTSHeader( | |
386 " max-age=0 ; incLudesUbdOmains ", &max_age, | |
387 &include_subdomains)); | |
388 expect_max_age = base::TimeDelta::FromSeconds(0); | |
389 EXPECT_EQ(expect_max_age, max_age); | |
390 EXPECT_TRUE(include_subdomains); | |
391 | |
392 EXPECT_TRUE(ParseHSTSHeader( | |
393 " max-age=999999999999999999999999999999999999999999999 ;" | |
394 " incLudesUbdOmains ", &max_age, &include_subdomains)); | |
395 expect_max_age = base::TimeDelta::FromSeconds( | |
396 kMaxHSTSAgeSecs); | |
397 EXPECT_EQ(expect_max_age, max_age); | |
398 EXPECT_TRUE(include_subdomains); | |
399 } | |
400 | |
401 static void TestValidPKPHeaders(HashValueTag tag) { | |
402 base::TimeDelta max_age; | |
403 base::TimeDelta expect_max_age; | |
404 bool include_subdomains; | |
405 HashValueVector hashes; | |
406 HashValueVector chain_hashes; | |
407 | |
408 // Set some fake "chain" hashes into chain_hashes | |
409 chain_hashes.push_back(GetTestHashValue(1, tag)); | |
410 chain_hashes.push_back(GetTestHashValue(2, tag)); | |
411 chain_hashes.push_back(GetTestHashValue(3, tag)); | |
412 | |
413 // The good pin must be in the chain, the backup pin must not be | |
414 std::string good_pin = GetTestPin(2, tag); | |
415 std::string good_pin2 = GetTestPin(3, tag); | |
416 std::string backup_pin = GetTestPin(4, tag); | |
417 | |
418 EXPECT_TRUE(ParseHPKPHeader( | |
419 "max-age=243; " + good_pin + ";" + backup_pin, | |
420 chain_hashes, &max_age, &include_subdomains, &hashes)); | |
421 expect_max_age = base::TimeDelta::FromSeconds(243); | |
422 EXPECT_EQ(expect_max_age, max_age); | |
423 EXPECT_FALSE(include_subdomains); | |
424 | |
425 EXPECT_TRUE(ParseHPKPHeader( | |
426 " " + good_pin + "; " + backup_pin + " ; Max-agE = 567", | |
427 chain_hashes, &max_age, &include_subdomains, &hashes)); | |
428 expect_max_age = base::TimeDelta::FromSeconds(567); | |
429 EXPECT_EQ(expect_max_age, max_age); | |
430 EXPECT_FALSE(include_subdomains); | |
431 | |
432 EXPECT_TRUE(ParseHPKPHeader( | |
433 "includeSubDOMAINS;" + good_pin + ";" + backup_pin + | |
434 " ; mAx-aGe = 890 ", | |
435 chain_hashes, &max_age, &include_subdomains, &hashes)); | |
436 expect_max_age = base::TimeDelta::FromSeconds(890); | |
437 EXPECT_EQ(expect_max_age, max_age); | |
438 EXPECT_TRUE(include_subdomains); | |
439 | |
440 EXPECT_TRUE(ParseHPKPHeader( | |
441 good_pin + ";" + backup_pin + "; max-age=123;IGNORED;", | |
442 chain_hashes, &max_age, &include_subdomains, &hashes)); | |
443 expect_max_age = base::TimeDelta::FromSeconds(123); | |
444 EXPECT_EQ(expect_max_age, max_age); | |
445 EXPECT_FALSE(include_subdomains); | |
446 | |
447 EXPECT_TRUE(ParseHPKPHeader( | |
448 "max-age=394082;" + backup_pin + ";" + good_pin + "; ", | |
449 chain_hashes, &max_age, &include_subdomains, &hashes)); | |
450 expect_max_age = base::TimeDelta::FromSeconds(394082); | |
451 EXPECT_EQ(expect_max_age, max_age); | |
452 EXPECT_FALSE(include_subdomains); | |
453 | |
454 EXPECT_TRUE(ParseHPKPHeader( | |
455 "max-age=39408299 ;" + backup_pin + ";" + good_pin + "; ", | |
456 chain_hashes, &max_age, &include_subdomains, &hashes)); | |
457 expect_max_age = base::TimeDelta::FromSeconds( | |
458 std::min(kMaxHSTSAgeSecs, static_cast<int64>(GG_INT64_C(39408299)))); | |
459 EXPECT_EQ(expect_max_age, max_age); | |
460 EXPECT_FALSE(include_subdomains); | |
461 | |
462 EXPECT_TRUE(ParseHPKPHeader( | |
463 "max-age=39408038 ; cybers=39408038 ; includeSubdomains; " + | |
464 good_pin + ";" + backup_pin + "; ", | |
465 chain_hashes, &max_age, &include_subdomains, &hashes)); | |
466 expect_max_age = base::TimeDelta::FromSeconds( | |
467 std::min(kMaxHSTSAgeSecs, static_cast<int64>(GG_INT64_C(394082038)))); | |
468 EXPECT_EQ(expect_max_age, max_age); | |
469 EXPECT_TRUE(include_subdomains); | |
470 | |
471 EXPECT_TRUE(ParseHPKPHeader( | |
472 " max-age=0 ; " + good_pin + ";" + backup_pin, | |
473 chain_hashes, &max_age, &include_subdomains, &hashes)); | |
474 expect_max_age = base::TimeDelta::FromSeconds(0); | |
475 EXPECT_EQ(expect_max_age, max_age); | |
476 EXPECT_FALSE(include_subdomains); | |
477 | |
478 EXPECT_TRUE(ParseHPKPHeader( | |
479 " max-age=0 ; includeSubdomains; " + good_pin + ";" + backup_pin, | |
480 chain_hashes, &max_age, &include_subdomains, &hashes)); | |
481 expect_max_age = base::TimeDelta::FromSeconds(0); | |
482 EXPECT_EQ(expect_max_age, max_age); | |
483 EXPECT_TRUE(include_subdomains); | |
484 | |
485 EXPECT_TRUE(ParseHPKPHeader( | |
486 " max-age=999999999999999999999999999999999999999999999 ; " + | |
487 backup_pin + ";" + good_pin + "; ", | |
488 chain_hashes, &max_age, &include_subdomains, &hashes)); | |
489 expect_max_age = base::TimeDelta::FromSeconds(kMaxHSTSAgeSecs); | |
490 EXPECT_EQ(expect_max_age, max_age); | |
491 EXPECT_FALSE(include_subdomains); | |
492 | |
493 // Test that parsing a different header resets the hashes. | |
494 hashes.clear(); | |
495 EXPECT_TRUE(ParseHPKPHeader( | |
496 " max-age=999; " + | |
497 backup_pin + ";" + good_pin + "; ", | |
498 chain_hashes, &max_age, &include_subdomains, &hashes)); | |
499 EXPECT_EQ(2u, hashes.size()); | |
500 EXPECT_TRUE(ParseHPKPHeader( | |
501 " max-age=999; " + backup_pin + ";" + good_pin2 + "; ", chain_hashes, | |
502 &max_age, &include_subdomains, &hashes)); | |
503 EXPECT_EQ(2u, hashes.size()); | |
504 } | |
505 | |
506 TEST_F(HttpSecurityHeadersTest, BogusPinsHeadersSHA1) { | |
507 TestBogusPinsHeaders(HASH_VALUE_SHA1); | |
508 } | |
509 | |
510 TEST_F(HttpSecurityHeadersTest, BogusPinsHeadersSHA256) { | |
511 TestBogusPinsHeaders(HASH_VALUE_SHA256); | |
512 } | |
513 | |
514 TEST_F(HttpSecurityHeadersTest, ValidPKPHeadersSHA1) { | |
515 TestValidPKPHeaders(HASH_VALUE_SHA1); | |
516 } | |
517 | |
518 TEST_F(HttpSecurityHeadersTest, ValidPKPHeadersSHA256) { | |
519 TestValidPKPHeaders(HASH_VALUE_SHA256); | |
520 } | |
521 | |
522 TEST_F(HttpSecurityHeadersTest, UpdateDynamicPKPOnly) { | |
523 TransportSecurityState state; | |
524 TransportSecurityState::DomainState static_domain_state; | |
525 | |
526 // docs.google.com has preloaded pins. | |
527 std::string domain = "docs.google.com"; | |
528 state.enable_static_pins_ = true; | |
529 EXPECT_TRUE( | |
530 state.GetStaticDomainState(domain, &static_domain_state)); | |
531 EXPECT_GT(static_domain_state.pkp.spki_hashes.size(), 1UL); | |
532 HashValueVector saved_hashes = static_domain_state.pkp.spki_hashes; | |
533 | |
534 // Add a header, which should only update the dynamic state. | |
535 HashValue good_hash = GetTestHashValue(1, HASH_VALUE_SHA1); | |
536 HashValue backup_hash = GetTestHashValue(2, HASH_VALUE_SHA1); | |
537 std::string good_pin = GetTestPin(1, HASH_VALUE_SHA1); | |
538 std::string backup_pin = GetTestPin(2, HASH_VALUE_SHA1); | |
539 std::string header = "max-age = 10000; " + good_pin + "; " + backup_pin; | |
540 | |
541 // Construct a fake SSLInfo that will pass AddHPKPHeader's checks. | |
542 SSLInfo ssl_info; | |
543 ssl_info.public_key_hashes.push_back(good_hash); | |
544 ssl_info.public_key_hashes.push_back(saved_hashes[0]); | |
545 EXPECT_TRUE(state.AddHPKPHeader(domain, header, ssl_info)); | |
546 | |
547 // Expect the static state to remain unchanged. | |
548 TransportSecurityState::DomainState new_static_domain_state; | |
549 EXPECT_TRUE(state.GetStaticDomainState( | |
550 domain, &new_static_domain_state)); | |
551 for (size_t i = 0; i < saved_hashes.size(); ++i) { | |
552 EXPECT_TRUE(HashValuesEqual(saved_hashes[i])( | |
553 new_static_domain_state.pkp.spki_hashes[i])); | |
554 } | |
555 | |
556 // Expect the dynamic state to reflect the header. | |
557 TransportSecurityState::DomainState dynamic_domain_state; | |
558 EXPECT_TRUE(state.GetDynamicDomainState(domain, &dynamic_domain_state)); | |
559 EXPECT_EQ(2UL, dynamic_domain_state.pkp.spki_hashes.size()); | |
560 | |
561 HashValueVector::const_iterator hash = | |
562 std::find_if(dynamic_domain_state.pkp.spki_hashes.begin(), | |
563 dynamic_domain_state.pkp.spki_hashes.end(), | |
564 HashValuesEqual(good_hash)); | |
565 EXPECT_NE(dynamic_domain_state.pkp.spki_hashes.end(), hash); | |
566 | |
567 hash = std::find_if(dynamic_domain_state.pkp.spki_hashes.begin(), | |
568 dynamic_domain_state.pkp.spki_hashes.end(), | |
569 HashValuesEqual(backup_hash)); | |
570 EXPECT_NE(dynamic_domain_state.pkp.spki_hashes.end(), hash); | |
571 | |
572 // Expect the overall state to reflect the header, too. | |
573 EXPECT_TRUE(state.HasPublicKeyPins(domain)); | |
574 HashValueVector hashes; | |
575 hashes.push_back(good_hash); | |
576 std::string failure_log; | |
577 const bool is_issued_by_known_root = true; | |
578 EXPECT_TRUE(state.CheckPublicKeyPins( | |
579 domain, is_issued_by_known_root, hashes, &failure_log)); | |
580 | |
581 TransportSecurityState::DomainState new_dynamic_domain_state; | |
582 EXPECT_TRUE(state.GetDynamicDomainState(domain, &new_dynamic_domain_state)); | |
583 EXPECT_EQ(2UL, new_dynamic_domain_state.pkp.spki_hashes.size()); | |
584 | |
585 hash = std::find_if(new_dynamic_domain_state.pkp.spki_hashes.begin(), | |
586 new_dynamic_domain_state.pkp.spki_hashes.end(), | |
587 HashValuesEqual(good_hash)); | |
588 EXPECT_NE(new_dynamic_domain_state.pkp.spki_hashes.end(), hash); | |
589 | |
590 hash = std::find_if(new_dynamic_domain_state.pkp.spki_hashes.begin(), | |
591 new_dynamic_domain_state.pkp.spki_hashes.end(), | |
592 HashValuesEqual(backup_hash)); | |
593 EXPECT_NE(new_dynamic_domain_state.pkp.spki_hashes.end(), hash); | |
594 } | |
595 | |
596 // Failing on win_chromium_rel. crbug.com/375538 | |
597 #if defined(OS_WIN) | |
598 #define MAYBE_UpdateDynamicPKPMaxAge0 DISABLED_UpdateDynamicPKPMaxAge0 | |
599 #else | |
600 #define MAYBE_UpdateDynamicPKPMaxAge0 UpdateDynamicPKPMaxAge0 | |
601 #endif | |
602 TEST_F(HttpSecurityHeadersTest, MAYBE_UpdateDynamicPKPMaxAge0) { | |
603 TransportSecurityState state; | |
604 TransportSecurityState::DomainState static_domain_state; | |
605 | |
606 // docs.google.com has preloaded pins. | |
607 std::string domain = "docs.google.com"; | |
608 state.enable_static_pins_ = true; | |
609 ASSERT_TRUE( | |
610 state.GetStaticDomainState(domain, &static_domain_state)); | |
611 EXPECT_GT(static_domain_state.pkp.spki_hashes.size(), 1UL); | |
612 HashValueVector saved_hashes = static_domain_state.pkp.spki_hashes; | |
613 | |
614 // Add a header, which should only update the dynamic state. | |
615 HashValue good_hash = GetTestHashValue(1, HASH_VALUE_SHA1); | |
616 std::string good_pin = GetTestPin(1, HASH_VALUE_SHA1); | |
617 std::string backup_pin = GetTestPin(2, HASH_VALUE_SHA1); | |
618 std::string header = "max-age = 10000; " + good_pin + "; " + backup_pin; | |
619 | |
620 // Construct a fake SSLInfo that will pass AddHPKPHeader's checks. | |
621 SSLInfo ssl_info; | |
622 ssl_info.public_key_hashes.push_back(good_hash); | |
623 ssl_info.public_key_hashes.push_back(saved_hashes[0]); | |
624 EXPECT_TRUE(state.AddHPKPHeader(domain, header, ssl_info)); | |
625 | |
626 // Expect the static state to remain unchanged. | |
627 TransportSecurityState::DomainState new_static_domain_state; | |
628 EXPECT_TRUE(state.GetStaticDomainState( | |
629 domain, &new_static_domain_state)); | |
630 EXPECT_EQ(saved_hashes.size(), | |
631 new_static_domain_state.pkp.spki_hashes.size()); | |
632 for (size_t i = 0; i < saved_hashes.size(); ++i) { | |
633 EXPECT_TRUE(HashValuesEqual(saved_hashes[i])( | |
634 new_static_domain_state.pkp.spki_hashes[i])); | |
635 } | |
636 | |
637 // Expect the dynamic state to have pins. | |
638 TransportSecurityState::DomainState new_dynamic_domain_state; | |
639 EXPECT_TRUE(state.GetDynamicDomainState(domain, &new_dynamic_domain_state)); | |
640 EXPECT_EQ(2UL, new_dynamic_domain_state.pkp.spki_hashes.size()); | |
641 EXPECT_TRUE(new_dynamic_domain_state.HasPublicKeyPins()); | |
642 | |
643 // Now set another header with max-age=0, and check that the pins are | |
644 // cleared in the dynamic state only. | |
645 header = "max-age = 0; " + good_pin + "; " + backup_pin; | |
646 EXPECT_TRUE(state.AddHPKPHeader(domain, header, ssl_info)); | |
647 | |
648 // Expect the static state to remain unchanged. | |
649 TransportSecurityState::DomainState new_static_domain_state2; | |
650 EXPECT_TRUE(state.GetStaticDomainState( | |
651 domain, &new_static_domain_state2)); | |
652 EXPECT_EQ(saved_hashes.size(), | |
653 new_static_domain_state2.pkp.spki_hashes.size()); | |
654 for (size_t i = 0; i < saved_hashes.size(); ++i) { | |
655 EXPECT_TRUE(HashValuesEqual(saved_hashes[i])( | |
656 new_static_domain_state2.pkp.spki_hashes[i])); | |
657 } | |
658 | |
659 // Expect the dynamic pins to be gone. | |
660 TransportSecurityState::DomainState new_dynamic_domain_state2; | |
661 EXPECT_FALSE(state.GetDynamicDomainState(domain, &new_dynamic_domain_state2)); | |
662 | |
663 // Expect the exact-matching static policy to continue to apply, even | |
664 // though dynamic policy has been removed. (This policy may change in the | |
665 // future, in which case this test must be updated.) | |
666 EXPECT_TRUE(state.HasPublicKeyPins(domain)); | |
667 EXPECT_TRUE(state.ShouldSSLErrorsBeFatal(domain)); | |
668 std::string failure_log; | |
669 // Damage the hashes to cause a pin validation failure. | |
670 new_static_domain_state2.pkp.spki_hashes[0].data()[0] ^= 0x80; | |
671 new_static_domain_state2.pkp.spki_hashes[1].data()[0] ^= 0x80; | |
672 const bool is_issued_by_known_root = true; | |
673 EXPECT_FALSE( | |
674 state.CheckPublicKeyPins(domain, | |
675 is_issued_by_known_root, | |
676 new_static_domain_state2.pkp.spki_hashes, | |
677 &failure_log)); | |
678 EXPECT_NE(0UL, failure_log.length()); | |
679 } | |
680 #undef MAYBE_UpdateDynamicPKPMaxAge0 | |
681 | |
682 // Tests that when a static HSTS and a static HPKP entry are present, adding a | |
683 // dynamic HSTS header does not clobber the static HPKP entry. Further, adding a | |
684 // dynamic HPKP entry could not affect the HSTS entry for the site. | |
685 TEST_F(HttpSecurityHeadersTest, NoClobberPins) { | |
686 TransportSecurityState state; | |
687 TransportSecurityState::DomainState domain_state; | |
688 | |
689 // accounts.google.com has preloaded pins. | |
690 std::string domain = "accounts.google.com"; | |
691 state.enable_static_pins_ = true; | |
692 | |
693 // Retrieve the DomainState as it is by default, including its known good | |
694 // pins. | |
695 EXPECT_TRUE(state.GetStaticDomainState(domain, &domain_state)); | |
696 HashValueVector saved_hashes = domain_state.pkp.spki_hashes; | |
697 EXPECT_TRUE(domain_state.ShouldUpgradeToSSL()); | |
698 EXPECT_TRUE(domain_state.HasPublicKeyPins()); | |
699 EXPECT_TRUE(state.ShouldUpgradeToSSL(domain)); | |
700 EXPECT_TRUE(state.HasPublicKeyPins(domain)); | |
701 | |
702 // Add a dynamic HSTS header. CheckPublicKeyPins should still pass when given | |
703 // the original |saved_hashes|, indicating that the static PKP data is still | |
704 // configured for the domain. | |
705 EXPECT_TRUE(state.AddHSTSHeader(domain, "includesubdomains; max-age=10000")); | |
706 EXPECT_TRUE(state.ShouldUpgradeToSSL(domain)); | |
707 std::string failure_log; | |
708 const bool is_issued_by_known_root = true; | |
709 EXPECT_TRUE(state.CheckPublicKeyPins(domain, | |
710 is_issued_by_known_root, | |
711 saved_hashes, | |
712 &failure_log)); | |
713 | |
714 // Add an HPKP header, which should only update the dynamic state. | |
715 HashValue good_hash = GetTestHashValue(1, HASH_VALUE_SHA1); | |
716 std::string good_pin = GetTestPin(1, HASH_VALUE_SHA1); | |
717 std::string backup_pin = GetTestPin(2, HASH_VALUE_SHA1); | |
718 std::string header = "max-age = 10000; " + good_pin + "; " + backup_pin; | |
719 | |
720 // Construct a fake SSLInfo that will pass AddHPKPHeader's checks. | |
721 SSLInfo ssl_info; | |
722 ssl_info.public_key_hashes.push_back(good_hash); | |
723 ssl_info.public_key_hashes.push_back(saved_hashes[0]); | |
724 EXPECT_TRUE(state.AddHPKPHeader(domain, header, ssl_info)); | |
725 | |
726 EXPECT_TRUE(state.AddHPKPHeader(domain, header, ssl_info)); | |
727 // HSTS should still be configured for this domain. | |
728 EXPECT_TRUE(domain_state.ShouldUpgradeToSSL()); | |
729 EXPECT_TRUE(state.ShouldUpgradeToSSL(domain)); | |
730 // The dynamic pins, which do not match |saved_hashes|, should take | |
731 // precedence over the static pins and cause the check to fail. | |
732 EXPECT_FALSE(state.CheckPublicKeyPins(domain, | |
733 is_issued_by_known_root, | |
734 saved_hashes, | |
735 &failure_log)); | |
736 } | |
737 | |
738 // Tests that seeing an invalid HPKP header leaves the existing one alone. | |
739 TEST_F(HttpSecurityHeadersTest, IgnoreInvalidHeaders) { | |
740 TransportSecurityState state; | |
741 | |
742 HashValue good_hash = GetTestHashValue(1, HASH_VALUE_SHA256); | |
743 std::string good_pin = GetTestPin(1, HASH_VALUE_SHA256); | |
744 std::string bad_pin = GetTestPin(2, HASH_VALUE_SHA256); | |
745 std::string backup_pin = GetTestPin(3, HASH_VALUE_SHA256); | |
746 | |
747 SSLInfo ssl_info; | |
748 ssl_info.public_key_hashes.push_back(good_hash); | |
749 | |
750 // Add a valid HPKP header. | |
751 EXPECT_TRUE(state.AddHPKPHeader( | |
752 "example.com", "max-age = 10000; " + good_pin + "; " + backup_pin, | |
753 ssl_info)); | |
754 | |
755 // Check the insertion was valid. | |
756 EXPECT_TRUE(state.HasPublicKeyPins("example.com")); | |
757 std::string failure_log; | |
758 bool is_issued_by_known_root = true; | |
759 EXPECT_TRUE(state.CheckPublicKeyPins("example.com", is_issued_by_known_root, | |
760 ssl_info.public_key_hashes, | |
761 &failure_log)); | |
762 | |
763 // Now assert an invalid one. This should fail. | |
764 EXPECT_FALSE(state.AddHPKPHeader( | |
765 "example.com", "max-age = 10000; " + bad_pin + "; " + backup_pin, | |
766 ssl_info)); | |
767 | |
768 // The old pins must still exist. | |
769 EXPECT_TRUE(state.HasPublicKeyPins("example.com")); | |
770 EXPECT_TRUE(state.CheckPublicKeyPins("example.com", is_issued_by_known_root, | |
771 ssl_info.public_key_hashes, | |
772 &failure_log)); | |
773 } | |
774 | |
775 }; // namespace net | |
OLD | NEW |