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.
7 #include "base/base64.h"
9 #include "base/strings/string_piece.h"
10 #include "crypto/sha2.h"
11 #include "net/base/test_completion_callback.h"
12 #include "net/http/http_security_headers.h"
13 #include "net/http/http_util.h"
14 #include "net/http/transport_security_state.h"
15 #include "net/log/net_log.h"
16 #include "net/ssl/ssl_info.h"
17 #include "testing/gtest/include/gtest/gtest.h"
23 HashValue
GetTestHashValue(uint8 label
, HashValueTag tag
) {
24 HashValue
hash_value(tag
);
25 memset(hash_value
.data(), label
, hash_value
.size());
29 std::string
GetTestPinImpl(uint8 label
, HashValueTag tag
, bool quoted
) {
30 HashValue hash_value
= GetTestHashValue(label
, tag
);
32 base::Base64Encode(base::StringPiece(
33 reinterpret_cast<char*>(hash_value
.data()), hash_value
.size()), &base64
);
36 switch (hash_value
.tag
) {
40 case HASH_VALUE_SHA256
:
44 NOTREACHED() << "Unknown HashValueTag " << hash_value
.tag
;
45 return std::string("ERROR");
55 std::string
GetTestPin(uint8 label
, HashValueTag tag
) {
56 return GetTestPinImpl(label
, tag
, true);
59 std::string
GetTestPinUnquoted(uint8 label
, HashValueTag tag
) {
60 return GetTestPinImpl(label
, tag
, false);
66 class HttpSecurityHeadersTest
: public testing::Test
{
70 TEST_F(HttpSecurityHeadersTest
, BogusHeaders
) {
71 base::TimeDelta max_age
;
72 bool include_subdomains
= 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
));
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
);
149 static void TestBogusPinsHeaders(HashValueTag tag
) {
150 base::TimeDelta max_age
;
151 bool include_subdomains
;
152 HashValueVector hashes
;
153 HashValueVector chain_hashes
;
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
));
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
);
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
,
196 EXPECT_FALSE(ParseHPKPHeader("max-age=3488a923 ", chain_hashes
,
197 &max_age
, &include_subdomains
, &hashes
));
198 EXPECT_FALSE(ParseHPKPHeader("max-ag=3488923pins=" + good_pin
+ "," +
200 chain_hashes
, &max_age
, &include_subdomains
,
202 EXPECT_FALSE(ParseHPKPHeader("max-aged=3488923" + backup_pin
,
203 chain_hashes
, &max_age
, &include_subdomains
,
205 EXPECT_FALSE(ParseHPKPHeader("max-aged=3488923; " + backup_pin
,
206 chain_hashes
, &max_age
, &include_subdomains
,
208 EXPECT_FALSE(ParseHPKPHeader("max-aged=3488923; " + backup_pin
+ ";" +
210 chain_hashes
, &max_age
, &include_subdomains
,
212 EXPECT_FALSE(ParseHPKPHeader("max-aged=3488923; " + good_pin
+ ";" +
214 chain_hashes
, &max_age
, &include_subdomains
,
216 EXPECT_FALSE(ParseHPKPHeader("max-aged=3488923; " + good_pin
,
217 chain_hashes
, &max_age
, &include_subdomains
,
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
,
232 EXPECT_FALSE(ParseHPKPHeader("max-age=34889.23", chain_hashes
, &max_age
,
233 &include_subdomains
, &hashes
));
235 ParseHPKPHeader("max-age=243; " + good_pin_unquoted
+ ";" + backup_pin
,
236 chain_hashes
, &max_age
, &include_subdomains
, &hashes
));
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);
244 TEST_F(HttpSecurityHeadersTest
, ValidSTSHeaders
) {
245 base::TimeDelta max_age
;
246 base::TimeDelta expect_max_age
;
247 bool include_subdomains
= false;
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
);
255 EXPECT_TRUE(ParseHSTSHeader("max-age=3488923;", &max_age
,
256 &include_subdomains
));
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
392 EXPECT_TRUE(ParseHSTSHeader(
393 " max-age=999999999999999999999999999999999999999999999 ;"
394 " incLudesUbdOmains ", &max_age
, &include_subdomains
));
395 expect_max_age
= base::TimeDelta::FromSeconds(
397 EXPECT_EQ(expect_max_age
, max_age
);
398 EXPECT_TRUE(include_subdomains
);
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
;
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
));
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
);
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
);
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
);
432 EXPECT_TRUE(ParseHPKPHeader(
433 "includeSubDOMAINS;" + good_pin
+ ";" + backup_pin
+
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
493 // Test that parsing a different header resets the hashes.
495 EXPECT_TRUE(ParseHPKPHeader(
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());
506 TEST_F(HttpSecurityHeadersTest
, BogusPinsHeadersSHA1
) {
507 TestBogusPinsHeaders(HASH_VALUE_SHA1
);
510 TEST_F(HttpSecurityHeadersTest
, BogusPinsHeadersSHA256
) {
511 TestBogusPinsHeaders(HASH_VALUE_SHA256
);
514 TEST_F(HttpSecurityHeadersTest
, ValidPKPHeadersSHA1
) {
515 TestValidPKPHeaders(HASH_VALUE_SHA1
);
518 TEST_F(HttpSecurityHeadersTest
, ValidPKPHeadersSHA256
) {
519 TestValidPKPHeaders(HASH_VALUE_SHA256
);
522 TEST_F(HttpSecurityHeadersTest
, UpdateDynamicPKPOnly
) {
523 TransportSecurityState state
;
524 TransportSecurityState::DomainState static_domain_state
;
526 // docs.google.com has preloaded pins.
527 std::string domain
= "docs.google.com";
528 state
.enable_static_pins_
= 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
;
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
;
541 // Construct a fake SSLInfo that will pass AddHPKPHeader's checks.
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
));
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
]));
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());
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
);
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
);
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
));
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());
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
);
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
);
596 TEST_F(HttpSecurityHeadersTest
, UpdateDynamicPKPMaxAge0
) {
597 TransportSecurityState state
;
598 TransportSecurityState::DomainState static_domain_state
;
600 // docs.google.com has preloaded pins.
601 std::string domain
= "docs.google.com";
602 state
.enable_static_pins_
= true;
604 state
.GetStaticDomainState(domain
, &static_domain_state
));
605 EXPECT_GT(static_domain_state
.pkp
.spki_hashes
.size(), 1UL);
606 HashValueVector saved_hashes
= static_domain_state
.pkp
.spki_hashes
;
608 // Add a header, which should only update the dynamic state.
609 HashValue good_hash
= GetTestHashValue(1, HASH_VALUE_SHA1
);
610 std::string good_pin
= GetTestPin(1, HASH_VALUE_SHA1
);
611 std::string backup_pin
= GetTestPin(2, HASH_VALUE_SHA1
);
612 std::string header
= "max-age = 10000; " + good_pin
+ "; " + backup_pin
;
614 // Construct a fake SSLInfo that will pass AddHPKPHeader's checks.
616 ssl_info
.public_key_hashes
.push_back(good_hash
);
617 ssl_info
.public_key_hashes
.push_back(saved_hashes
[0]);
618 EXPECT_TRUE(state
.AddHPKPHeader(domain
, header
, ssl_info
));
620 // Expect the static state to remain unchanged.
621 TransportSecurityState::DomainState new_static_domain_state
;
622 EXPECT_TRUE(state
.GetStaticDomainState(
623 domain
, &new_static_domain_state
));
624 EXPECT_EQ(saved_hashes
.size(),
625 new_static_domain_state
.pkp
.spki_hashes
.size());
626 for (size_t i
= 0; i
< saved_hashes
.size(); ++i
) {
627 EXPECT_TRUE(HashValuesEqual(saved_hashes
[i
])(
628 new_static_domain_state
.pkp
.spki_hashes
[i
]));
631 // Expect the dynamic state to have pins.
632 TransportSecurityState::DomainState new_dynamic_domain_state
;
633 EXPECT_TRUE(state
.GetDynamicDomainState(domain
, &new_dynamic_domain_state
));
634 EXPECT_EQ(2UL, new_dynamic_domain_state
.pkp
.spki_hashes
.size());
635 EXPECT_TRUE(new_dynamic_domain_state
.HasPublicKeyPins());
637 // Now set another header with max-age=0, and check that the pins are
638 // cleared in the dynamic state only.
639 header
= "max-age = 0; " + good_pin
+ "; " + backup_pin
;
640 EXPECT_TRUE(state
.AddHPKPHeader(domain
, header
, ssl_info
));
642 // Expect the static state to remain unchanged.
643 TransportSecurityState::DomainState new_static_domain_state2
;
644 EXPECT_TRUE(state
.GetStaticDomainState(
645 domain
, &new_static_domain_state2
));
646 EXPECT_EQ(saved_hashes
.size(),
647 new_static_domain_state2
.pkp
.spki_hashes
.size());
648 for (size_t i
= 0; i
< saved_hashes
.size(); ++i
) {
649 EXPECT_TRUE(HashValuesEqual(saved_hashes
[i
])(
650 new_static_domain_state2
.pkp
.spki_hashes
[i
]));
653 // Expect the dynamic pins to be gone.
654 TransportSecurityState::DomainState new_dynamic_domain_state2
;
655 EXPECT_FALSE(state
.GetDynamicDomainState(domain
, &new_dynamic_domain_state2
));
657 // Expect the exact-matching static policy to continue to apply, even
658 // though dynamic policy has been removed. (This policy may change in the
659 // future, in which case this test must be updated.)
660 EXPECT_TRUE(state
.HasPublicKeyPins(domain
));
661 EXPECT_TRUE(state
.ShouldSSLErrorsBeFatal(domain
));
662 std::string failure_log
;
663 // Damage the hashes to cause a pin validation failure.
664 new_static_domain_state2
.pkp
.spki_hashes
[0].data()[0] ^= 0x80;
665 new_static_domain_state2
.pkp
.spki_hashes
[1].data()[0] ^= 0x80;
666 const bool is_issued_by_known_root
= true;
668 state
.CheckPublicKeyPins(domain
,
669 is_issued_by_known_root
,
670 new_static_domain_state2
.pkp
.spki_hashes
,
672 EXPECT_NE(0UL, failure_log
.length());
675 // Tests that when a static HSTS and a static HPKP entry are present, adding a
676 // dynamic HSTS header does not clobber the static HPKP entry. Further, adding a
677 // dynamic HPKP entry could not affect the HSTS entry for the site.
678 TEST_F(HttpSecurityHeadersTest
, NoClobberPins
) {
679 TransportSecurityState state
;
680 TransportSecurityState::DomainState domain_state
;
682 // accounts.google.com has preloaded pins.
683 std::string domain
= "accounts.google.com";
684 state
.enable_static_pins_
= true;
686 // Retrieve the DomainState as it is by default, including its known good
688 EXPECT_TRUE(state
.GetStaticDomainState(domain
, &domain_state
));
689 HashValueVector saved_hashes
= domain_state
.pkp
.spki_hashes
;
690 EXPECT_TRUE(domain_state
.ShouldUpgradeToSSL());
691 EXPECT_TRUE(domain_state
.HasPublicKeyPins());
692 EXPECT_TRUE(state
.ShouldUpgradeToSSL(domain
));
693 EXPECT_TRUE(state
.HasPublicKeyPins(domain
));
695 // Add a dynamic HSTS header. CheckPublicKeyPins should still pass when given
696 // the original |saved_hashes|, indicating that the static PKP data is still
697 // configured for the domain.
698 EXPECT_TRUE(state
.AddHSTSHeader(domain
, "includesubdomains; max-age=10000"));
699 EXPECT_TRUE(state
.ShouldUpgradeToSSL(domain
));
700 std::string failure_log
;
701 const bool is_issued_by_known_root
= true;
702 EXPECT_TRUE(state
.CheckPublicKeyPins(domain
,
703 is_issued_by_known_root
,
707 // Add an HPKP header, which should only update the dynamic state.
708 HashValue good_hash
= GetTestHashValue(1, HASH_VALUE_SHA1
);
709 std::string good_pin
= GetTestPin(1, HASH_VALUE_SHA1
);
710 std::string backup_pin
= GetTestPin(2, HASH_VALUE_SHA1
);
711 std::string header
= "max-age = 10000; " + good_pin
+ "; " + backup_pin
;
713 // Construct a fake SSLInfo that will pass AddHPKPHeader's checks.
715 ssl_info
.public_key_hashes
.push_back(good_hash
);
716 ssl_info
.public_key_hashes
.push_back(saved_hashes
[0]);
717 EXPECT_TRUE(state
.AddHPKPHeader(domain
, header
, ssl_info
));
719 EXPECT_TRUE(state
.AddHPKPHeader(domain
, header
, ssl_info
));
720 // HSTS should still be configured for this domain.
721 EXPECT_TRUE(domain_state
.ShouldUpgradeToSSL());
722 EXPECT_TRUE(state
.ShouldUpgradeToSSL(domain
));
723 // The dynamic pins, which do not match |saved_hashes|, should take
724 // precedence over the static pins and cause the check to fail.
725 EXPECT_FALSE(state
.CheckPublicKeyPins(domain
,
726 is_issued_by_known_root
,
731 // Tests that seeing an invalid HPKP header leaves the existing one alone.
732 TEST_F(HttpSecurityHeadersTest
, IgnoreInvalidHeaders
) {
733 TransportSecurityState state
;
735 HashValue good_hash
= GetTestHashValue(1, HASH_VALUE_SHA256
);
736 std::string good_pin
= GetTestPin(1, HASH_VALUE_SHA256
);
737 std::string bad_pin
= GetTestPin(2, HASH_VALUE_SHA256
);
738 std::string backup_pin
= GetTestPin(3, HASH_VALUE_SHA256
);
741 ssl_info
.public_key_hashes
.push_back(good_hash
);
743 // Add a valid HPKP header.
744 EXPECT_TRUE(state
.AddHPKPHeader(
745 "example.com", "max-age = 10000; " + good_pin
+ "; " + backup_pin
,
748 // Check the insertion was valid.
749 EXPECT_TRUE(state
.HasPublicKeyPins("example.com"));
750 std::string failure_log
;
751 bool is_issued_by_known_root
= true;
752 EXPECT_TRUE(state
.CheckPublicKeyPins("example.com", is_issued_by_known_root
,
753 ssl_info
.public_key_hashes
,
756 // Now assert an invalid one. This should fail.
757 EXPECT_FALSE(state
.AddHPKPHeader(
758 "example.com", "max-age = 10000; " + bad_pin
+ "; " + backup_pin
,
761 // The old pins must still exist.
762 EXPECT_TRUE(state
.HasPublicKeyPins("example.com"));
763 EXPECT_TRUE(state
.CheckPublicKeyPins("example.com", is_issued_by_known_root
,
764 ssl_info
.public_key_hashes
,