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.
8 #include "base/base64.h"
10 #include "base/strings/string_piece.h"
11 #include "crypto/sha2.h"
12 #include "net/base/host_port_pair.h"
13 #include "net/base/test_completion_callback.h"
14 #include "net/http/http_security_headers.h"
15 #include "net/http/http_util.h"
16 #include "net/http/transport_security_state.h"
17 #include "net/log/net_log.h"
18 #include "net/ssl/ssl_info.h"
19 #include "testing/gtest/include/gtest/gtest.h"
25 HashValue
GetTestHashValue(uint8 label
, HashValueTag tag
) {
26 HashValue
hash_value(tag
);
27 memset(hash_value
.data(), label
, hash_value
.size());
31 std::string
GetTestPinImpl(uint8 label
, HashValueTag tag
, bool quoted
) {
32 HashValue hash_value
= GetTestHashValue(label
, tag
);
34 base::Base64Encode(base::StringPiece(
35 reinterpret_cast<char*>(hash_value
.data()), hash_value
.size()), &base64
);
38 switch (hash_value
.tag
) {
42 case HASH_VALUE_SHA256
:
46 NOTREACHED() << "Unknown HashValueTag " << hash_value
.tag
;
47 return std::string("ERROR");
57 std::string
GetTestPin(uint8 label
, HashValueTag tag
) {
58 return GetTestPinImpl(label
, tag
, true);
61 std::string
GetTestPinUnquoted(uint8 label
, HashValueTag tag
) {
62 return GetTestPinImpl(label
, tag
, false);
68 class HttpSecurityHeadersTest
: public testing::Test
{
72 TEST_F(HttpSecurityHeadersTest
, BogusHeaders
) {
73 base::TimeDelta max_age
;
74 bool include_subdomains
= false;
77 ParseHSTSHeader(std::string(), &max_age
, &include_subdomains
));
78 EXPECT_FALSE(ParseHSTSHeader(" ", &max_age
, &include_subdomains
));
79 EXPECT_FALSE(ParseHSTSHeader("abc", &max_age
, &include_subdomains
));
80 EXPECT_FALSE(ParseHSTSHeader(" abc", &max_age
, &include_subdomains
));
81 EXPECT_FALSE(ParseHSTSHeader(" abc ", &max_age
, &include_subdomains
));
82 EXPECT_FALSE(ParseHSTSHeader("max-age", &max_age
, &include_subdomains
));
83 EXPECT_FALSE(ParseHSTSHeader(" max-age", &max_age
,
84 &include_subdomains
));
85 EXPECT_FALSE(ParseHSTSHeader(" max-age ", &max_age
,
86 &include_subdomains
));
87 EXPECT_FALSE(ParseHSTSHeader("max-age=", &max_age
, &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 = ", &max_age
,
95 &include_subdomains
));
96 EXPECT_FALSE(ParseHSTSHeader(" max-age = xy", &max_age
,
97 &include_subdomains
));
98 EXPECT_FALSE(ParseHSTSHeader(" max-age = 3488a923", &max_age
,
99 &include_subdomains
));
100 EXPECT_FALSE(ParseHSTSHeader("max-age=3488a923 ", &max_age
,
101 &include_subdomains
));
102 EXPECT_FALSE(ParseHSTSHeader("max-ag=3488923", &max_age
,
103 &include_subdomains
));
104 EXPECT_FALSE(ParseHSTSHeader("max-aged=3488923", &max_age
,
105 &include_subdomains
));
106 EXPECT_FALSE(ParseHSTSHeader("max-age==3488923", &max_age
,
107 &include_subdomains
));
108 EXPECT_FALSE(ParseHSTSHeader("amax-age=3488923", &max_age
,
109 &include_subdomains
));
110 EXPECT_FALSE(ParseHSTSHeader("max-age=-3488923", &max_age
,
111 &include_subdomains
));
112 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923 e", &max_age
,
113 &include_subdomains
));
114 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923 includesubdomain",
115 &max_age
, &include_subdomains
));
116 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923includesubdomains",
117 &max_age
, &include_subdomains
));
118 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923=includesubdomains",
119 &max_age
, &include_subdomains
));
120 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923 includesubdomainx",
121 &max_age
, &include_subdomains
));
122 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923 includesubdomain=",
123 &max_age
, &include_subdomains
));
124 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923 includesubdomain=true",
125 &max_age
, &include_subdomains
));
126 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923 includesubdomainsx",
127 &max_age
, &include_subdomains
));
128 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923 includesubdomains x",
129 &max_age
, &include_subdomains
));
130 EXPECT_FALSE(ParseHSTSHeader("max-age=34889.23 includesubdomains",
131 &max_age
, &include_subdomains
));
132 EXPECT_FALSE(ParseHSTSHeader("max-age=34889 includesubdomains",
133 &max_age
, &include_subdomains
));
134 EXPECT_FALSE(ParseHSTSHeader(";;;; ;;;",
135 &max_age
, &include_subdomains
));
136 EXPECT_FALSE(ParseHSTSHeader(";;;; includeSubDomains;;;",
137 &max_age
, &include_subdomains
));
138 EXPECT_FALSE(ParseHSTSHeader(" includeSubDomains; ",
139 &max_age
, &include_subdomains
));
140 EXPECT_FALSE(ParseHSTSHeader(";",
141 &max_age
, &include_subdomains
));
142 EXPECT_FALSE(ParseHSTSHeader("max-age; ;",
143 &max_age
, &include_subdomains
));
145 // Check the out args were not updated by checking the default
146 // values for its predictable fields.
147 EXPECT_EQ(0, max_age
.InSeconds());
148 EXPECT_FALSE(include_subdomains
);
151 static void TestBogusPinsHeaders(HashValueTag tag
) {
152 base::TimeDelta max_age
;
153 bool include_subdomains
;
154 HashValueVector hashes
;
155 HashValueVector chain_hashes
;
158 // Set some fake "chain" hashes
159 chain_hashes
.push_back(GetTestHashValue(1, tag
));
160 chain_hashes
.push_back(GetTestHashValue(2, tag
));
161 chain_hashes
.push_back(GetTestHashValue(3, tag
));
163 // The good pin must be in the chain, the backup pin must not be
164 std::string good_pin
= GetTestPin(2, tag
);
165 std::string good_pin_unquoted
= GetTestPinUnquoted(2, tag
);
166 std::string backup_pin
= GetTestPin(4, tag
);
168 EXPECT_FALSE(ParseHPKPHeader(std::string(), chain_hashes
, &max_age
,
169 &include_subdomains
, &hashes
, &report_uri
));
170 EXPECT_FALSE(ParseHPKPHeader(" ", chain_hashes
, &max_age
,
171 &include_subdomains
, &hashes
, &report_uri
));
172 EXPECT_FALSE(ParseHPKPHeader("abc", chain_hashes
, &max_age
,
173 &include_subdomains
, &hashes
, &report_uri
));
174 EXPECT_FALSE(ParseHPKPHeader(" abc", chain_hashes
, &max_age
,
175 &include_subdomains
, &hashes
, &report_uri
));
176 EXPECT_FALSE(ParseHPKPHeader(" abc ", chain_hashes
, &max_age
,
177 &include_subdomains
, &hashes
, &report_uri
));
178 EXPECT_FALSE(ParseHPKPHeader("max-age", chain_hashes
, &max_age
,
179 &include_subdomains
, &hashes
, &report_uri
));
180 EXPECT_FALSE(ParseHPKPHeader(" max-age", chain_hashes
, &max_age
,
181 &include_subdomains
, &hashes
, &report_uri
));
182 EXPECT_FALSE(ParseHPKPHeader(" max-age ", chain_hashes
, &max_age
,
183 &include_subdomains
, &hashes
, &report_uri
));
184 EXPECT_FALSE(ParseHPKPHeader("max-age=", chain_hashes
, &max_age
,
185 &include_subdomains
, &hashes
, &report_uri
));
186 EXPECT_FALSE(ParseHPKPHeader(" max-age=", chain_hashes
, &max_age
,
187 &include_subdomains
, &hashes
, &report_uri
));
188 EXPECT_FALSE(ParseHPKPHeader(" max-age =", chain_hashes
, &max_age
,
189 &include_subdomains
, &hashes
, &report_uri
));
190 EXPECT_FALSE(ParseHPKPHeader(" max-age= ", chain_hashes
, &max_age
,
191 &include_subdomains
, &hashes
, &report_uri
));
192 EXPECT_FALSE(ParseHPKPHeader(" max-age = ", chain_hashes
, &max_age
,
193 &include_subdomains
, &hashes
, &report_uri
));
194 EXPECT_FALSE(ParseHPKPHeader(" max-age = xy", chain_hashes
, &max_age
,
195 &include_subdomains
, &hashes
, &report_uri
));
196 EXPECT_FALSE(ParseHPKPHeader(" max-age = 3488a923", chain_hashes
,
197 &max_age
, &include_subdomains
, &hashes
,
199 EXPECT_FALSE(ParseHPKPHeader("max-age=3488a923 ", chain_hashes
, &max_age
,
200 &include_subdomains
, &hashes
, &report_uri
));
201 EXPECT_FALSE(ParseHPKPHeader(
202 "max-ag=3488923pins=" + good_pin
+ "," + backup_pin
, chain_hashes
,
203 &max_age
, &include_subdomains
, &hashes
, &report_uri
));
204 EXPECT_FALSE(ParseHPKPHeader("max-age=3488923;pins=" + good_pin
+ "," +
205 backup_pin
+ "report-uri=\"http://foo.com\"",
206 chain_hashes
, &max_age
, &include_subdomains
,
207 &hashes
, &report_uri
));
208 EXPECT_FALSE(ParseHPKPHeader("max-aged=3488923" + backup_pin
, chain_hashes
,
209 &max_age
, &include_subdomains
, &hashes
,
211 EXPECT_FALSE(ParseHPKPHeader("max-aged=3488923; " + backup_pin
, chain_hashes
,
212 &max_age
, &include_subdomains
, &hashes
,
214 EXPECT_FALSE(ParseHPKPHeader(
215 "max-aged=3488923; " + backup_pin
+ ";" + backup_pin
, chain_hashes
,
216 &max_age
, &include_subdomains
, &hashes
, &report_uri
));
217 EXPECT_FALSE(ParseHPKPHeader("max-aged=3488923; " + good_pin
+ ";" + good_pin
,
218 chain_hashes
, &max_age
, &include_subdomains
,
219 &hashes
, &report_uri
));
220 EXPECT_FALSE(ParseHPKPHeader("max-aged=3488923; " + good_pin
, chain_hashes
,
221 &max_age
, &include_subdomains
, &hashes
,
223 EXPECT_FALSE(ParseHPKPHeader("max-age==3488923", chain_hashes
, &max_age
,
224 &include_subdomains
, &hashes
, &report_uri
));
225 EXPECT_FALSE(ParseHPKPHeader("amax-age=3488923", chain_hashes
, &max_age
,
226 &include_subdomains
, &hashes
, &report_uri
));
227 EXPECT_FALSE(ParseHPKPHeader("max-age=-3488923", chain_hashes
, &max_age
,
228 &include_subdomains
, &hashes
, &report_uri
));
229 EXPECT_FALSE(ParseHPKPHeader("max-age=3488923;", chain_hashes
, &max_age
,
230 &include_subdomains
, &hashes
, &report_uri
));
231 EXPECT_FALSE(ParseHPKPHeader("max-age=3488923 e", chain_hashes
, &max_age
,
232 &include_subdomains
, &hashes
, &report_uri
));
233 EXPECT_FALSE(ParseHPKPHeader("max-age=3488923 includesubdomain",
234 chain_hashes
, &max_age
, &include_subdomains
,
235 &hashes
, &report_uri
));
236 EXPECT_FALSE(ParseHPKPHeader(
237 "max-age=3488923 report-uri=\"http://foo.com\"", chain_hashes
,
238 &max_age
, &include_subdomains
, &hashes
, &report_uri
));
239 EXPECT_FALSE(ParseHPKPHeader("max-age=34889.23", chain_hashes
, &max_age
,
240 &include_subdomains
, &hashes
, &report_uri
));
241 EXPECT_FALSE(ParseHPKPHeader(
242 "max-age=243; " + good_pin_unquoted
+ ";" + backup_pin
, chain_hashes
,
243 &max_age
, &include_subdomains
, &hashes
, &report_uri
));
244 EXPECT_FALSE(ParseHPKPHeader(
245 "max-age=243; " + good_pin
+ ";" + backup_pin
+ ";report-uri=;",
246 chain_hashes
, &max_age
, &include_subdomains
, &hashes
, &report_uri
));
247 EXPECT_FALSE(ParseHPKPHeader("max-age=243; " + good_pin
+ ";" + backup_pin
+
248 ";report-uri=http://foo.com;",
249 chain_hashes
, &max_age
, &include_subdomains
,
250 &hashes
, &report_uri
));
251 EXPECT_FALSE(ParseHPKPHeader(
252 "max-age=243; " + good_pin
+ ";" + backup_pin
+ ";report-uri=''",
253 chain_hashes
, &max_age
, &include_subdomains
, &hashes
, &report_uri
));
255 // Test that the parser rejects misquoted strings.
256 EXPECT_FALSE(ParseHPKPHeader("max-age=999; " + backup_pin
+ "; " + good_pin
+
257 "; report-uri=\"http://foo;bar\'",
258 chain_hashes
, &max_age
, &include_subdomains
,
259 &hashes
, &report_uri
));
261 // Test that the parser rejects invalid report-uris.
262 EXPECT_FALSE(ParseHPKPHeader("max-age=999; " + backup_pin
+ "; " + good_pin
+
263 "; report-uri=\"foo;bar\'",
264 chain_hashes
, &max_age
, &include_subdomains
,
265 &hashes
, &report_uri
));
267 // Check the out args were not updated by checking the default
268 // values for its predictable fields.
269 EXPECT_EQ(0, max_age
.InSeconds());
270 EXPECT_EQ(hashes
.size(), (size_t)0);
273 TEST_F(HttpSecurityHeadersTest
, ValidSTSHeaders
) {
274 base::TimeDelta max_age
;
275 base::TimeDelta expect_max_age
;
276 bool include_subdomains
= false;
278 EXPECT_TRUE(ParseHSTSHeader("max-age=243", &max_age
,
279 &include_subdomains
));
280 expect_max_age
= base::TimeDelta::FromSeconds(243);
281 EXPECT_EQ(expect_max_age
, max_age
);
282 EXPECT_FALSE(include_subdomains
);
284 EXPECT_TRUE(ParseHSTSHeader("max-age=3488923;", &max_age
,
285 &include_subdomains
));
287 EXPECT_TRUE(ParseHSTSHeader(" Max-agE = 567", &max_age
,
288 &include_subdomains
));
289 expect_max_age
= base::TimeDelta::FromSeconds(567);
290 EXPECT_EQ(expect_max_age
, max_age
);
291 EXPECT_FALSE(include_subdomains
);
293 EXPECT_TRUE(ParseHSTSHeader(" mAx-aGe = 890 ", &max_age
,
294 &include_subdomains
));
295 expect_max_age
= base::TimeDelta::FromSeconds(890);
296 EXPECT_EQ(expect_max_age
, max_age
);
297 EXPECT_FALSE(include_subdomains
);
299 EXPECT_TRUE(ParseHSTSHeader("max-age=123;incLudesUbdOmains", &max_age
,
300 &include_subdomains
));
301 expect_max_age
= base::TimeDelta::FromSeconds(123);
302 EXPECT_EQ(expect_max_age
, max_age
);
303 EXPECT_TRUE(include_subdomains
);
305 EXPECT_TRUE(ParseHSTSHeader("incLudesUbdOmains; max-age=123", &max_age
,
306 &include_subdomains
));
307 expect_max_age
= base::TimeDelta::FromSeconds(123);
308 EXPECT_EQ(expect_max_age
, max_age
);
309 EXPECT_TRUE(include_subdomains
);
311 EXPECT_TRUE(ParseHSTSHeader(" incLudesUbdOmains; max-age=123",
312 &max_age
, &include_subdomains
));
313 expect_max_age
= base::TimeDelta::FromSeconds(123);
314 EXPECT_EQ(expect_max_age
, max_age
);
315 EXPECT_TRUE(include_subdomains
);
317 EXPECT_TRUE(ParseHSTSHeader(
318 " incLudesUbdOmains; max-age=123; pumpkin=kitten", &max_age
,
319 &include_subdomains
));
320 expect_max_age
= base::TimeDelta::FromSeconds(123);
321 EXPECT_EQ(expect_max_age
, max_age
);
322 EXPECT_TRUE(include_subdomains
);
324 EXPECT_TRUE(ParseHSTSHeader(
325 " pumpkin=894; incLudesUbdOmains; max-age=123 ", &max_age
,
326 &include_subdomains
));
327 expect_max_age
= base::TimeDelta::FromSeconds(123);
328 EXPECT_EQ(expect_max_age
, max_age
);
329 EXPECT_TRUE(include_subdomains
);
331 EXPECT_TRUE(ParseHSTSHeader(
332 " pumpkin; incLudesUbdOmains; max-age=123 ", &max_age
,
333 &include_subdomains
));
334 expect_max_age
= base::TimeDelta::FromSeconds(123);
335 EXPECT_EQ(expect_max_age
, max_age
);
336 EXPECT_TRUE(include_subdomains
);
338 EXPECT_TRUE(ParseHSTSHeader(
339 " pumpkin; incLudesUbdOmains; max-age=\"123\" ", &max_age
,
340 &include_subdomains
));
341 expect_max_age
= base::TimeDelta::FromSeconds(123);
342 EXPECT_EQ(expect_max_age
, max_age
);
343 EXPECT_TRUE(include_subdomains
);
345 EXPECT_TRUE(ParseHSTSHeader(
346 "animal=\"squirrel; distinguished\"; incLudesUbdOmains; max-age=123",
347 &max_age
, &include_subdomains
));
348 expect_max_age
= base::TimeDelta::FromSeconds(123);
349 EXPECT_EQ(expect_max_age
, max_age
);
350 EXPECT_TRUE(include_subdomains
);
352 EXPECT_TRUE(ParseHSTSHeader("max-age=394082; incLudesUbdOmains",
353 &max_age
, &include_subdomains
));
354 expect_max_age
= base::TimeDelta::FromSeconds(394082);
355 EXPECT_EQ(expect_max_age
, max_age
);
356 EXPECT_TRUE(include_subdomains
);
358 EXPECT_TRUE(ParseHSTSHeader(
359 "max-age=39408299 ;incLudesUbdOmains", &max_age
,
360 &include_subdomains
));
361 expect_max_age
= base::TimeDelta::FromSeconds(
362 std::min(kMaxHSTSAgeSecs
, static_cast<int64
>(INT64_C(39408299))));
363 EXPECT_EQ(expect_max_age
, max_age
);
364 EXPECT_TRUE(include_subdomains
);
366 EXPECT_TRUE(ParseHSTSHeader(
367 "max-age=394082038 ; incLudesUbdOmains", &max_age
,
368 &include_subdomains
));
369 expect_max_age
= base::TimeDelta::FromSeconds(
370 std::min(kMaxHSTSAgeSecs
, static_cast<int64
>(INT64_C(394082038))));
371 EXPECT_EQ(expect_max_age
, max_age
);
372 EXPECT_TRUE(include_subdomains
);
374 EXPECT_TRUE(ParseHSTSHeader(
375 "max-age=394082038 ; incLudesUbdOmains;", &max_age
,
376 &include_subdomains
));
377 expect_max_age
= base::TimeDelta::FromSeconds(
378 std::min(kMaxHSTSAgeSecs
, static_cast<int64
>(INT64_C(394082038))));
379 EXPECT_EQ(expect_max_age
, max_age
);
380 EXPECT_TRUE(include_subdomains
);
382 EXPECT_TRUE(ParseHSTSHeader(
383 ";; max-age=394082038 ; incLudesUbdOmains; ;", &max_age
,
384 &include_subdomains
));
385 expect_max_age
= base::TimeDelta::FromSeconds(
386 std::min(kMaxHSTSAgeSecs
, static_cast<int64
>(INT64_C(394082038))));
387 EXPECT_EQ(expect_max_age
, max_age
);
388 EXPECT_TRUE(include_subdomains
);
390 EXPECT_TRUE(ParseHSTSHeader(
391 ";; max-age=394082038 ;", &max_age
,
392 &include_subdomains
));
393 expect_max_age
= base::TimeDelta::FromSeconds(
394 std::min(kMaxHSTSAgeSecs
, static_cast<int64
>(INT64_C(394082038))));
395 EXPECT_EQ(expect_max_age
, max_age
);
396 EXPECT_FALSE(include_subdomains
);
398 EXPECT_TRUE(ParseHSTSHeader(
399 ";; ; ; max-age=394082038;;; includeSubdomains ;; ;", &max_age
,
400 &include_subdomains
));
401 expect_max_age
= base::TimeDelta::FromSeconds(
402 std::min(kMaxHSTSAgeSecs
, static_cast<int64
>(INT64_C(394082038))));
403 EXPECT_EQ(expect_max_age
, max_age
);
404 EXPECT_TRUE(include_subdomains
);
406 EXPECT_TRUE(ParseHSTSHeader(
407 "incLudesUbdOmains ; max-age=394082038 ;;", &max_age
,
408 &include_subdomains
));
409 expect_max_age
= base::TimeDelta::FromSeconds(
410 std::min(kMaxHSTSAgeSecs
, static_cast<int64
>(INT64_C(394082038))));
411 EXPECT_EQ(expect_max_age
, max_age
);
412 EXPECT_TRUE(include_subdomains
);
414 EXPECT_TRUE(ParseHSTSHeader(
415 " max-age=0 ; incLudesUbdOmains ", &max_age
,
416 &include_subdomains
));
417 expect_max_age
= base::TimeDelta::FromSeconds(0);
418 EXPECT_EQ(expect_max_age
, max_age
);
419 EXPECT_TRUE(include_subdomains
);
421 EXPECT_TRUE(ParseHSTSHeader(
422 " max-age=999999999999999999999999999999999999999999999 ;"
423 " incLudesUbdOmains ", &max_age
, &include_subdomains
));
424 expect_max_age
= base::TimeDelta::FromSeconds(
426 EXPECT_EQ(expect_max_age
, max_age
);
427 EXPECT_TRUE(include_subdomains
);
430 static void TestValidPKPHeaders(HashValueTag tag
) {
431 base::TimeDelta max_age
;
432 base::TimeDelta expect_max_age
;
433 bool include_subdomains
;
434 HashValueVector hashes
;
435 HashValueVector chain_hashes
;
436 GURL expect_report_uri
;
439 // Set some fake "chain" hashes into chain_hashes
440 chain_hashes
.push_back(GetTestHashValue(1, tag
));
441 chain_hashes
.push_back(GetTestHashValue(2, tag
));
442 chain_hashes
.push_back(GetTestHashValue(3, tag
));
444 // The good pin must be in the chain, the backup pin must not be
445 std::string good_pin
= GetTestPin(2, tag
);
446 std::string good_pin2
= GetTestPin(3, tag
);
447 std::string backup_pin
= GetTestPin(4, tag
);
449 EXPECT_TRUE(ParseHPKPHeader("max-age=243; " + good_pin
+ ";" + backup_pin
,
450 chain_hashes
, &max_age
, &include_subdomains
,
451 &hashes
, &report_uri
));
452 expect_max_age
= base::TimeDelta::FromSeconds(243);
453 EXPECT_EQ(expect_max_age
, max_age
);
454 EXPECT_FALSE(include_subdomains
);
455 EXPECT_TRUE(report_uri
.is_empty());
457 EXPECT_TRUE(ParseHPKPHeader("max-age=243; " + good_pin
+ ";" + backup_pin
+
458 "; report-uri= \"http://example.test/foo\"",
459 chain_hashes
, &max_age
, &include_subdomains
,
460 &hashes
, &report_uri
));
461 expect_max_age
= base::TimeDelta::FromSeconds(243);
462 expect_report_uri
= GURL("http://example.test/foo");
463 EXPECT_EQ(expect_max_age
, max_age
);
464 EXPECT_FALSE(include_subdomains
);
465 EXPECT_EQ(expect_report_uri
, report_uri
);
467 EXPECT_TRUE(ParseHPKPHeader(
468 " " + good_pin
+ "; " + backup_pin
+
469 " ; Max-agE = 567; repOrT-URi = \"http://example.test/foo\"",
470 chain_hashes
, &max_age
, &include_subdomains
, &hashes
, &report_uri
));
471 expect_max_age
= base::TimeDelta::FromSeconds(567);
472 expect_report_uri
= GURL("http://example.test/foo");
473 EXPECT_EQ(expect_max_age
, max_age
);
474 EXPECT_FALSE(include_subdomains
);
475 EXPECT_EQ(expect_report_uri
, report_uri
);
477 EXPECT_TRUE(ParseHPKPHeader("includeSubDOMAINS;" + good_pin
+ ";" +
478 backup_pin
+ " ; mAx-aGe = 890 ",
479 chain_hashes
, &max_age
, &include_subdomains
,
480 &hashes
, &report_uri
));
481 expect_max_age
= base::TimeDelta::FromSeconds(890);
482 EXPECT_EQ(expect_max_age
, max_age
);
483 EXPECT_TRUE(include_subdomains
);
485 EXPECT_TRUE(ParseHPKPHeader(
486 good_pin
+ ";" + backup_pin
+ "; max-age=123;IGNORED;", chain_hashes
,
487 &max_age
, &include_subdomains
, &hashes
, &report_uri
));
488 expect_max_age
= base::TimeDelta::FromSeconds(123);
489 EXPECT_EQ(expect_max_age
, max_age
);
490 EXPECT_FALSE(include_subdomains
);
492 EXPECT_TRUE(ParseHPKPHeader(
493 "max-age=394082;" + backup_pin
+ ";" + good_pin
+ "; ", chain_hashes
,
494 &max_age
, &include_subdomains
, &hashes
, &report_uri
));
495 expect_max_age
= base::TimeDelta::FromSeconds(394082);
496 EXPECT_EQ(expect_max_age
, max_age
);
497 EXPECT_FALSE(include_subdomains
);
499 EXPECT_TRUE(ParseHPKPHeader(
500 "max-age=39408299 ;" + backup_pin
+ ";" + good_pin
+ "; ", chain_hashes
,
501 &max_age
, &include_subdomains
, &hashes
, &report_uri
));
502 expect_max_age
= base::TimeDelta::FromSeconds(
503 std::min(kMaxHSTSAgeSecs
, static_cast<int64
>(INT64_C(39408299))));
504 EXPECT_EQ(expect_max_age
, max_age
);
505 EXPECT_FALSE(include_subdomains
);
507 EXPECT_TRUE(ParseHPKPHeader(
508 "max-age=39408038 ; cybers=39408038 ; includeSubdomains; " +
509 good_pin
+ ";" + backup_pin
+ "; ",
510 chain_hashes
, &max_age
, &include_subdomains
, &hashes
, &report_uri
));
511 expect_max_age
= base::TimeDelta::FromSeconds(
512 std::min(kMaxHSTSAgeSecs
, static_cast<int64
>(INT64_C(394082038))));
513 EXPECT_EQ(expect_max_age
, max_age
);
514 EXPECT_TRUE(include_subdomains
);
516 EXPECT_TRUE(ParseHPKPHeader(" max-age=0 ; " + good_pin
+ ";" + backup_pin
,
517 chain_hashes
, &max_age
, &include_subdomains
,
518 &hashes
, &report_uri
));
519 expect_max_age
= base::TimeDelta::FromSeconds(0);
520 EXPECT_EQ(expect_max_age
, max_age
);
521 EXPECT_FALSE(include_subdomains
);
523 EXPECT_TRUE(ParseHPKPHeader(
524 " max-age=0 ; includeSubdomains; " + good_pin
+ ";" + backup_pin
,
525 chain_hashes
, &max_age
, &include_subdomains
, &hashes
, &report_uri
));
526 expect_max_age
= base::TimeDelta::FromSeconds(0);
527 EXPECT_EQ(expect_max_age
, max_age
);
528 EXPECT_TRUE(include_subdomains
);
530 EXPECT_TRUE(ParseHPKPHeader(
531 " max-age=999999999999999999999999999999999999999999999 ; " +
532 backup_pin
+ ";" + good_pin
+ "; ",
533 chain_hashes
, &max_age
, &include_subdomains
, &hashes
, &report_uri
));
534 expect_max_age
= base::TimeDelta::FromSeconds(kMaxHSTSAgeSecs
);
535 EXPECT_EQ(expect_max_age
, max_age
);
536 EXPECT_FALSE(include_subdomains
);
538 EXPECT_TRUE(ParseHPKPHeader(
539 " max-age=999999999999999999999999999999999999999999999 ; " +
540 backup_pin
+ ";" + good_pin
+
541 "; report-uri=\"http://example.test/foo\"",
542 chain_hashes
, &max_age
, &include_subdomains
, &hashes
, &report_uri
));
543 expect_max_age
= base::TimeDelta::FromSeconds(kMaxHSTSAgeSecs
);
544 expect_report_uri
= GURL("http://example.test/foo");
545 EXPECT_EQ(expect_max_age
, max_age
);
546 EXPECT_FALSE(include_subdomains
);
547 EXPECT_EQ(expect_report_uri
, report_uri
);
549 // Test that parsing a different header resets the hashes.
551 EXPECT_TRUE(ParseHPKPHeader(
552 " max-age=999; " + backup_pin
+ ";" + good_pin
+ "; ", chain_hashes
,
553 &max_age
, &include_subdomains
, &hashes
, &report_uri
));
554 EXPECT_EQ(2u, hashes
.size());
555 EXPECT_TRUE(ParseHPKPHeader(
556 " max-age=999; " + backup_pin
+ ";" + good_pin2
+ "; ", chain_hashes
,
557 &max_age
, &include_subdomains
, &hashes
, &report_uri
));
558 EXPECT_EQ(2u, hashes
.size());
560 // Test that the parser correctly parses an unencoded ';' inside a
561 // quoted report-uri.
562 EXPECT_TRUE(ParseHPKPHeader("max-age=999; " + backup_pin
+ "; " + good_pin
+
563 "; report-uri=\"http://foo.com/?;bar\"",
564 chain_hashes
, &max_age
, &include_subdomains
,
565 &hashes
, &report_uri
));
566 expect_max_age
= base::TimeDelta::FromSeconds(999);
567 expect_report_uri
= GURL("http://foo.com/?;bar");
568 EXPECT_EQ(expect_max_age
, max_age
);
569 EXPECT_FALSE(include_subdomains
);
570 EXPECT_EQ(expect_report_uri
, report_uri
);
572 // Test that the parser correctly parses a report-uri with a >0x7f
574 std::string uri
= "http://foo.com/";
576 expect_report_uri
= GURL(uri
);
577 EXPECT_TRUE(ParseHPKPHeader("max-age=999; " + backup_pin
+ "; " + good_pin
+
578 "; report-uri=\"" + uri
+ "\"",
579 chain_hashes
, &max_age
, &include_subdomains
,
580 &hashes
, &report_uri
));
581 expect_max_age
= base::TimeDelta::FromSeconds(999);
582 EXPECT_EQ(expect_max_age
, max_age
);
583 EXPECT_FALSE(include_subdomains
);
584 EXPECT_EQ(expect_report_uri
, report_uri
);
586 // Test that the parser allows quoted max-age values.
587 EXPECT_TRUE(ParseHPKPHeader("max-age='999'; " + backup_pin
+ "; " + good_pin
,
588 chain_hashes
, &max_age
, &include_subdomains
,
589 &hashes
, &report_uri
));
590 expect_max_age
= base::TimeDelta::FromSeconds(999);
591 EXPECT_EQ(expect_max_age
, max_age
);
592 EXPECT_FALSE(include_subdomains
);
594 // Test that the parser handles escaped values.
595 expect_report_uri
= GURL("http://foo.com'a");
596 EXPECT_TRUE(ParseHPKPHeader("max-age=999; " + backup_pin
+ "; " + good_pin
+
597 "; report-uri='http://foo.com\\'\\a'",
598 chain_hashes
, &max_age
, &include_subdomains
,
599 &hashes
, &report_uri
));
600 expect_max_age
= base::TimeDelta::FromSeconds(999);
601 EXPECT_EQ(expect_max_age
, max_age
);
602 EXPECT_FALSE(include_subdomains
);
603 EXPECT_EQ(expect_report_uri
, report_uri
);
606 TEST_F(HttpSecurityHeadersTest
, BogusPinsHeadersSHA1
) {
607 TestBogusPinsHeaders(HASH_VALUE_SHA1
);
610 TEST_F(HttpSecurityHeadersTest
, BogusPinsHeadersSHA256
) {
611 TestBogusPinsHeaders(HASH_VALUE_SHA256
);
614 TEST_F(HttpSecurityHeadersTest
, ValidPKPHeadersSHA1
) {
615 TestValidPKPHeaders(HASH_VALUE_SHA1
);
618 TEST_F(HttpSecurityHeadersTest
, ValidPKPHeadersSHA256
) {
619 TestValidPKPHeaders(HASH_VALUE_SHA256
);
622 TEST_F(HttpSecurityHeadersTest
, UpdateDynamicPKPOnly
) {
623 TransportSecurityState state
;
624 TransportSecurityState::STSState static_sts_state
;
625 TransportSecurityState::PKPState static_pkp_state
;
627 // docs.google.com has preloaded pins.
628 std::string domain
= "docs.google.com";
629 state
.enable_static_pins_
= true;
631 state
.GetStaticDomainState(domain
, &static_sts_state
, &static_pkp_state
));
632 EXPECT_GT(static_pkp_state
.spki_hashes
.size(), 1UL);
633 HashValueVector saved_hashes
= static_pkp_state
.spki_hashes
;
635 // Add a header, which should only update the dynamic state.
636 HashValue good_hash
= GetTestHashValue(1, HASH_VALUE_SHA1
);
637 HashValue backup_hash
= GetTestHashValue(2, HASH_VALUE_SHA1
);
638 std::string good_pin
= GetTestPin(1, HASH_VALUE_SHA1
);
639 std::string backup_pin
= GetTestPin(2, HASH_VALUE_SHA1
);
640 GURL
report_uri("http://google.com");
641 std::string header
= "max-age = 10000; " + good_pin
+ "; " + backup_pin
+
642 ";report-uri=\"" + report_uri
.spec() + "\"";
644 // Construct a fake SSLInfo that will pass AddHPKPHeader's checks.
646 ssl_info
.public_key_hashes
.push_back(good_hash
);
647 ssl_info
.public_key_hashes
.push_back(saved_hashes
[0]);
648 EXPECT_TRUE(state
.AddHPKPHeader(domain
, header
, ssl_info
));
650 // Expect the static state to remain unchanged.
651 TransportSecurityState::STSState new_static_sts_state
;
652 TransportSecurityState::PKPState new_static_pkp_state
;
653 EXPECT_TRUE(state
.GetStaticDomainState(domain
, &new_static_sts_state
,
654 &new_static_pkp_state
));
655 for (size_t i
= 0; i
< saved_hashes
.size(); ++i
) {
657 HashValuesEqual(saved_hashes
[i
])(new_static_pkp_state
.spki_hashes
[i
]));
660 // Expect the dynamic state to reflect the header.
661 TransportSecurityState::PKPState dynamic_pkp_state
;
662 EXPECT_TRUE(state
.GetDynamicPKPState(domain
, &dynamic_pkp_state
));
663 EXPECT_EQ(2UL, dynamic_pkp_state
.spki_hashes
.size());
664 EXPECT_EQ(report_uri
, dynamic_pkp_state
.report_uri
);
666 HashValueVector::const_iterator hash
= std::find_if(
667 dynamic_pkp_state
.spki_hashes
.begin(),
668 dynamic_pkp_state
.spki_hashes
.end(), HashValuesEqual(good_hash
));
669 EXPECT_NE(dynamic_pkp_state
.spki_hashes
.end(), hash
);
671 hash
= std::find_if(dynamic_pkp_state
.spki_hashes
.begin(),
672 dynamic_pkp_state
.spki_hashes
.end(),
673 HashValuesEqual(backup_hash
));
674 EXPECT_NE(dynamic_pkp_state
.spki_hashes
.end(), hash
);
676 // Expect the overall state to reflect the header, too.
677 EXPECT_TRUE(state
.HasPublicKeyPins(domain
));
678 HashValueVector hashes
;
679 hashes
.push_back(good_hash
);
680 std::string failure_log
;
681 const bool is_issued_by_known_root
= true;
682 HostPortPair
domain_port(domain
, 443);
683 EXPECT_TRUE(state
.CheckPublicKeyPins(
684 domain_port
, is_issued_by_known_root
, hashes
, nullptr, nullptr,
685 TransportSecurityState::DISABLE_PIN_REPORTS
, &failure_log
));
687 TransportSecurityState::PKPState new_dynamic_pkp_state
;
688 EXPECT_TRUE(state
.GetDynamicPKPState(domain
, &new_dynamic_pkp_state
));
689 EXPECT_EQ(2UL, new_dynamic_pkp_state
.spki_hashes
.size());
690 EXPECT_EQ(report_uri
, new_dynamic_pkp_state
.report_uri
);
692 hash
= std::find_if(new_dynamic_pkp_state
.spki_hashes
.begin(),
693 new_dynamic_pkp_state
.spki_hashes
.end(),
694 HashValuesEqual(good_hash
));
695 EXPECT_NE(new_dynamic_pkp_state
.spki_hashes
.end(), hash
);
697 hash
= std::find_if(new_dynamic_pkp_state
.spki_hashes
.begin(),
698 new_dynamic_pkp_state
.spki_hashes
.end(),
699 HashValuesEqual(backup_hash
));
700 EXPECT_NE(new_dynamic_pkp_state
.spki_hashes
.end(), hash
);
703 TEST_F(HttpSecurityHeadersTest
, UpdateDynamicPKPMaxAge0
) {
704 TransportSecurityState state
;
705 TransportSecurityState::STSState static_sts_state
;
706 TransportSecurityState::PKPState static_pkp_state
;
708 // docs.google.com has preloaded pins.
709 std::string domain
= "docs.google.com";
710 state
.enable_static_pins_
= true;
712 state
.GetStaticDomainState(domain
, &static_sts_state
, &static_pkp_state
));
713 EXPECT_GT(static_pkp_state
.spki_hashes
.size(), 1UL);
714 HashValueVector saved_hashes
= static_pkp_state
.spki_hashes
;
716 // Add a header, which should only update the dynamic state.
717 HashValue good_hash
= GetTestHashValue(1, HASH_VALUE_SHA1
);
718 std::string good_pin
= GetTestPin(1, HASH_VALUE_SHA1
);
719 std::string backup_pin
= GetTestPin(2, HASH_VALUE_SHA1
);
720 std::string header
= "max-age = 10000; " + good_pin
+ "; " + backup_pin
;
722 // Construct a fake SSLInfo that will pass AddHPKPHeader's checks.
724 ssl_info
.public_key_hashes
.push_back(good_hash
);
725 ssl_info
.public_key_hashes
.push_back(saved_hashes
[0]);
726 EXPECT_TRUE(state
.AddHPKPHeader(domain
, header
, ssl_info
));
728 // Expect the static state to remain unchanged.
729 TransportSecurityState::STSState new_static_sts_state
;
730 TransportSecurityState::PKPState new_static_pkp_state
;
731 EXPECT_TRUE(state
.GetStaticDomainState(domain
, &new_static_sts_state
,
732 &new_static_pkp_state
));
733 EXPECT_EQ(saved_hashes
.size(), new_static_pkp_state
.spki_hashes
.size());
734 for (size_t i
= 0; i
< saved_hashes
.size(); ++i
) {
736 HashValuesEqual(saved_hashes
[i
])(new_static_pkp_state
.spki_hashes
[i
]));
739 // Expect the dynamic state to have pins.
740 TransportSecurityState::PKPState new_dynamic_pkp_state
;
741 EXPECT_TRUE(state
.GetDynamicPKPState(domain
, &new_dynamic_pkp_state
));
742 EXPECT_EQ(2UL, new_dynamic_pkp_state
.spki_hashes
.size());
743 EXPECT_TRUE(new_dynamic_pkp_state
.HasPublicKeyPins());
745 // Now set another header with max-age=0, and check that the pins are
746 // cleared in the dynamic state only.
747 header
= "max-age = 0; " + good_pin
+ "; " + backup_pin
;
748 EXPECT_TRUE(state
.AddHPKPHeader(domain
, header
, ssl_info
));
750 // Expect the static state to remain unchanged.
751 TransportSecurityState::PKPState new_static_pkp_state2
;
752 EXPECT_TRUE(state
.GetStaticDomainState(domain
, &static_sts_state
,
753 &new_static_pkp_state2
));
754 EXPECT_EQ(saved_hashes
.size(), new_static_pkp_state2
.spki_hashes
.size());
755 for (size_t i
= 0; i
< saved_hashes
.size(); ++i
) {
757 HashValuesEqual(saved_hashes
[i
])(new_static_pkp_state2
.spki_hashes
[i
]));
760 // Expect the dynamic pins to be gone.
761 TransportSecurityState::PKPState new_dynamic_pkp_state2
;
762 EXPECT_FALSE(state
.GetDynamicPKPState(domain
, &new_dynamic_pkp_state2
));
764 // Expect the exact-matching static policy to continue to apply, even
765 // though dynamic policy has been removed. (This policy may change in the
766 // future, in which case this test must be updated.)
767 EXPECT_TRUE(state
.HasPublicKeyPins(domain
));
768 EXPECT_TRUE(state
.ShouldSSLErrorsBeFatal(domain
));
769 std::string failure_log
;
771 // Damage the hashes to cause a pin validation failure.
772 new_static_pkp_state2
.spki_hashes
[0].data()[0] ^= 0x80;
773 new_static_pkp_state2
.spki_hashes
[1].data()[0] ^= 0x80;
774 new_static_pkp_state2
.spki_hashes
[2].data()[0] ^= 0x80;
776 const bool is_issued_by_known_root
= true;
777 HostPortPair
domain_port(domain
, 443);
778 EXPECT_FALSE(state
.CheckPublicKeyPins(
779 domain_port
, is_issued_by_known_root
, new_static_pkp_state2
.spki_hashes
,
780 nullptr, nullptr, TransportSecurityState::DISABLE_PIN_REPORTS
,
782 EXPECT_NE(0UL, failure_log
.length());
785 // Tests that when a static HSTS and a static HPKP entry are present, adding a
786 // dynamic HSTS header does not clobber the static HPKP entry. Further, adding a
787 // dynamic HPKP entry could not affect the HSTS entry for the site.
788 TEST_F(HttpSecurityHeadersTest
, NoClobberPins
) {
789 TransportSecurityState state
;
790 TransportSecurityState::STSState sts_state
;
791 TransportSecurityState::PKPState pkp_state
;
793 // accounts.google.com has preloaded pins.
794 std::string domain
= "accounts.google.com";
795 state
.enable_static_pins_
= true;
797 // Retrieve the static STS and PKP states as it is by default, including its
799 EXPECT_TRUE(state
.GetStaticDomainState(domain
, &sts_state
, &pkp_state
));
800 HashValueVector saved_hashes
= pkp_state
.spki_hashes
;
801 EXPECT_TRUE(sts_state
.ShouldUpgradeToSSL());
802 EXPECT_TRUE(pkp_state
.HasPublicKeyPins());
803 EXPECT_TRUE(state
.ShouldUpgradeToSSL(domain
));
804 EXPECT_TRUE(state
.HasPublicKeyPins(domain
));
806 // Add a dynamic HSTS header. CheckPublicKeyPins should still pass when given
807 // the original |saved_hashes|, indicating that the static PKP data is still
808 // configured for the domain.
809 EXPECT_TRUE(state
.AddHSTSHeader(domain
, "includesubdomains; max-age=10000"));
810 EXPECT_TRUE(state
.ShouldUpgradeToSSL(domain
));
811 std::string failure_log
;
812 const bool is_issued_by_known_root
= true;
813 HostPortPair
domain_port(domain
, 443);
814 EXPECT_TRUE(state
.CheckPublicKeyPins(
815 domain_port
, is_issued_by_known_root
, saved_hashes
, nullptr, nullptr,
816 TransportSecurityState::DISABLE_PIN_REPORTS
, &failure_log
));
818 // Add an HPKP header, which should only update the dynamic state.
819 HashValue good_hash
= GetTestHashValue(1, HASH_VALUE_SHA1
);
820 std::string good_pin
= GetTestPin(1, HASH_VALUE_SHA1
);
821 std::string backup_pin
= GetTestPin(2, HASH_VALUE_SHA1
);
822 std::string header
= "max-age = 10000; " + good_pin
+ "; " + backup_pin
;
824 // Construct a fake SSLInfo that will pass AddHPKPHeader's checks.
826 ssl_info
.public_key_hashes
.push_back(good_hash
);
827 ssl_info
.public_key_hashes
.push_back(saved_hashes
[0]);
828 EXPECT_TRUE(state
.AddHPKPHeader(domain
, header
, ssl_info
));
830 EXPECT_TRUE(state
.AddHPKPHeader(domain
, header
, ssl_info
));
831 // HSTS should still be configured for this domain.
832 EXPECT_TRUE(sts_state
.ShouldUpgradeToSSL());
833 EXPECT_TRUE(state
.ShouldUpgradeToSSL(domain
));
834 // The dynamic pins, which do not match |saved_hashes|, should take
835 // precedence over the static pins and cause the check to fail.
836 EXPECT_FALSE(state
.CheckPublicKeyPins(
837 domain_port
, is_issued_by_known_root
, saved_hashes
, nullptr, nullptr,
838 TransportSecurityState::DISABLE_PIN_REPORTS
, &failure_log
));
841 // Tests that seeing an invalid HPKP header leaves the existing one alone.
842 TEST_F(HttpSecurityHeadersTest
, IgnoreInvalidHeaders
) {
843 TransportSecurityState state
;
845 HashValue good_hash
= GetTestHashValue(1, HASH_VALUE_SHA256
);
846 std::string good_pin
= GetTestPin(1, HASH_VALUE_SHA256
);
847 std::string bad_pin
= GetTestPin(2, HASH_VALUE_SHA256
);
848 std::string backup_pin
= GetTestPin(3, HASH_VALUE_SHA256
);
851 ssl_info
.public_key_hashes
.push_back(good_hash
);
853 // Add a valid HPKP header.
854 EXPECT_TRUE(state
.AddHPKPHeader(
855 "example.com", "max-age = 10000; " + good_pin
+ "; " + backup_pin
,
858 // Check the insertion was valid.
859 EXPECT_TRUE(state
.HasPublicKeyPins("example.com"));
860 std::string failure_log
;
861 bool is_issued_by_known_root
= true;
862 HostPortPair
domain_port("example.com", 443);
863 EXPECT_TRUE(state
.CheckPublicKeyPins(
864 domain_port
, is_issued_by_known_root
, ssl_info
.public_key_hashes
, nullptr,
865 nullptr, TransportSecurityState::DISABLE_PIN_REPORTS
, &failure_log
));
867 // Now assert an invalid one. This should fail.
868 EXPECT_FALSE(state
.AddHPKPHeader(
869 "example.com", "max-age = 10000; " + bad_pin
+ "; " + backup_pin
,
872 // The old pins must still exist.
873 EXPECT_TRUE(state
.HasPublicKeyPins("example.com"));
874 EXPECT_TRUE(state
.CheckPublicKeyPins(
875 domain_port
, is_issued_by_known_root
, ssl_info
.public_key_hashes
, nullptr,
876 nullptr, TransportSecurityState::DISABLE_PIN_REPORTS
, &failure_log
));