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/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/log/net_log.h"
17 #include "net/ssl/ssl_info.h"
18 #include "testing/gtest/include/gtest/gtest.h"
24 HashValue
GetTestHashValue(uint8 label
, HashValueTag tag
) {
25 HashValue
hash_value(tag
);
26 memset(hash_value
.data(), label
, hash_value
.size());
30 std::string
GetTestPinImpl(uint8 label
, HashValueTag tag
, bool quoted
) {
31 HashValue hash_value
= GetTestHashValue(label
, tag
);
33 base::Base64Encode(base::StringPiece(
34 reinterpret_cast<char*>(hash_value
.data()), hash_value
.size()), &base64
);
37 switch (hash_value
.tag
) {
41 case HASH_VALUE_SHA256
:
45 NOTREACHED() << "Unknown HashValueTag " << hash_value
.tag
;
46 return std::string("ERROR");
56 std::string
GetTestPin(uint8 label
, HashValueTag tag
) {
57 return GetTestPinImpl(label
, tag
, true);
60 std::string
GetTestPinUnquoted(uint8 label
, HashValueTag tag
) {
61 return GetTestPinImpl(label
, tag
, false);
67 class HttpSecurityHeadersTest
: public testing::Test
{
71 TEST_F(HttpSecurityHeadersTest
, BogusHeaders
) {
72 base::TimeDelta max_age
;
73 bool include_subdomains
= false;
76 ParseHSTSHeader(std::string(), &max_age
, &include_subdomains
));
77 EXPECT_FALSE(ParseHSTSHeader(" ", &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(" abc ", &max_age
, &include_subdomains
));
81 EXPECT_FALSE(ParseHSTSHeader("max-age", &max_age
, &include_subdomains
));
82 EXPECT_FALSE(ParseHSTSHeader(" max-age", &max_age
,
83 &include_subdomains
));
84 EXPECT_FALSE(ParseHSTSHeader(" max-age ", &max_age
,
85 &include_subdomains
));
86 EXPECT_FALSE(ParseHSTSHeader("max-age=", &max_age
, &include_subdomains
));
87 EXPECT_FALSE(ParseHSTSHeader(" max-age=", &max_age
,
88 &include_subdomains
));
89 EXPECT_FALSE(ParseHSTSHeader(" max-age =", &max_age
,
90 &include_subdomains
));
91 EXPECT_FALSE(ParseHSTSHeader(" max-age= ", &max_age
,
92 &include_subdomains
));
93 EXPECT_FALSE(ParseHSTSHeader(" max-age = ", &max_age
,
94 &include_subdomains
));
95 EXPECT_FALSE(ParseHSTSHeader(" max-age = xy", &max_age
,
96 &include_subdomains
));
97 EXPECT_FALSE(ParseHSTSHeader(" max-age = 3488a923", &max_age
,
98 &include_subdomains
));
99 EXPECT_FALSE(ParseHSTSHeader("max-age=3488a923 ", &max_age
,
100 &include_subdomains
));
101 EXPECT_FALSE(ParseHSTSHeader("max-ag=3488923", &max_age
,
102 &include_subdomains
));
103 EXPECT_FALSE(ParseHSTSHeader("max-aged=3488923", &max_age
,
104 &include_subdomains
));
105 EXPECT_FALSE(ParseHSTSHeader("max-age==3488923", &max_age
,
106 &include_subdomains
));
107 EXPECT_FALSE(ParseHSTSHeader("amax-age=3488923", &max_age
,
108 &include_subdomains
));
109 EXPECT_FALSE(ParseHSTSHeader("max-age=-3488923", &max_age
,
110 &include_subdomains
));
111 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923 e", &max_age
,
112 &include_subdomains
));
113 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923 includesubdomain",
114 &max_age
, &include_subdomains
));
115 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923includesubdomains",
116 &max_age
, &include_subdomains
));
117 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923=includesubdomains",
118 &max_age
, &include_subdomains
));
119 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923 includesubdomainx",
120 &max_age
, &include_subdomains
));
121 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923 includesubdomain=",
122 &max_age
, &include_subdomains
));
123 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923 includesubdomain=true",
124 &max_age
, &include_subdomains
));
125 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923 includesubdomainsx",
126 &max_age
, &include_subdomains
));
127 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923 includesubdomains x",
128 &max_age
, &include_subdomains
));
129 EXPECT_FALSE(ParseHSTSHeader("max-age=34889.23 includesubdomains",
130 &max_age
, &include_subdomains
));
131 EXPECT_FALSE(ParseHSTSHeader("max-age=34889 includesubdomains",
132 &max_age
, &include_subdomains
));
133 EXPECT_FALSE(ParseHSTSHeader(";;;; ;;;",
134 &max_age
, &include_subdomains
));
135 EXPECT_FALSE(ParseHSTSHeader(";;;; includeSubDomains;;;",
136 &max_age
, &include_subdomains
));
137 EXPECT_FALSE(ParseHSTSHeader(" includeSubDomains; ",
138 &max_age
, &include_subdomains
));
139 EXPECT_FALSE(ParseHSTSHeader(";",
140 &max_age
, &include_subdomains
));
141 EXPECT_FALSE(ParseHSTSHeader("max-age; ;",
142 &max_age
, &include_subdomains
));
144 // Check the out args were not updated by checking the default
145 // values for its predictable fields.
146 EXPECT_EQ(0, max_age
.InSeconds());
147 EXPECT_FALSE(include_subdomains
);
150 static void TestBogusPinsHeaders(HashValueTag tag
) {
151 base::TimeDelta max_age
;
152 bool include_subdomains
;
153 HashValueVector hashes
;
154 HashValueVector chain_hashes
;
157 // Set some fake "chain" hashes
158 chain_hashes
.push_back(GetTestHashValue(1, tag
));
159 chain_hashes
.push_back(GetTestHashValue(2, tag
));
160 chain_hashes
.push_back(GetTestHashValue(3, tag
));
162 // The good pin must be in the chain, the backup pin must not be
163 std::string good_pin
= GetTestPin(2, tag
);
164 std::string good_pin_unquoted
= GetTestPinUnquoted(2, tag
);
165 std::string backup_pin
= GetTestPin(4, tag
);
167 EXPECT_FALSE(ParseHPKPHeader(std::string(), chain_hashes
, &max_age
,
168 &include_subdomains
, &hashes
, &report_uri
));
169 EXPECT_FALSE(ParseHPKPHeader(" ", chain_hashes
, &max_age
,
170 &include_subdomains
, &hashes
, &report_uri
));
171 EXPECT_FALSE(ParseHPKPHeader("abc", chain_hashes
, &max_age
,
172 &include_subdomains
, &hashes
, &report_uri
));
173 EXPECT_FALSE(ParseHPKPHeader(" abc", chain_hashes
, &max_age
,
174 &include_subdomains
, &hashes
, &report_uri
));
175 EXPECT_FALSE(ParseHPKPHeader(" abc ", chain_hashes
, &max_age
,
176 &include_subdomains
, &hashes
, &report_uri
));
177 EXPECT_FALSE(ParseHPKPHeader("max-age", chain_hashes
, &max_age
,
178 &include_subdomains
, &hashes
, &report_uri
));
179 EXPECT_FALSE(ParseHPKPHeader(" max-age", chain_hashes
, &max_age
,
180 &include_subdomains
, &hashes
, &report_uri
));
181 EXPECT_FALSE(ParseHPKPHeader(" max-age ", chain_hashes
, &max_age
,
182 &include_subdomains
, &hashes
, &report_uri
));
183 EXPECT_FALSE(ParseHPKPHeader("max-age=", chain_hashes
, &max_age
,
184 &include_subdomains
, &hashes
, &report_uri
));
185 EXPECT_FALSE(ParseHPKPHeader(" max-age=", chain_hashes
, &max_age
,
186 &include_subdomains
, &hashes
, &report_uri
));
187 EXPECT_FALSE(ParseHPKPHeader(" max-age =", chain_hashes
, &max_age
,
188 &include_subdomains
, &hashes
, &report_uri
));
189 EXPECT_FALSE(ParseHPKPHeader(" max-age= ", chain_hashes
, &max_age
,
190 &include_subdomains
, &hashes
, &report_uri
));
191 EXPECT_FALSE(ParseHPKPHeader(" max-age = ", chain_hashes
, &max_age
,
192 &include_subdomains
, &hashes
, &report_uri
));
193 EXPECT_FALSE(ParseHPKPHeader(" max-age = xy", chain_hashes
, &max_age
,
194 &include_subdomains
, &hashes
, &report_uri
));
195 EXPECT_FALSE(ParseHPKPHeader(" max-age = 3488a923", chain_hashes
,
196 &max_age
, &include_subdomains
, &hashes
,
198 EXPECT_FALSE(ParseHPKPHeader("max-age=3488a923 ", chain_hashes
, &max_age
,
199 &include_subdomains
, &hashes
, &report_uri
));
200 EXPECT_FALSE(ParseHPKPHeader(
201 "max-ag=3488923pins=" + good_pin
+ "," + backup_pin
, chain_hashes
,
202 &max_age
, &include_subdomains
, &hashes
, &report_uri
));
203 EXPECT_FALSE(ParseHPKPHeader("max-age=3488923;pins=" + good_pin
+ "," +
204 backup_pin
+ "report-uri=\"http://foo.com\"",
205 chain_hashes
, &max_age
, &include_subdomains
,
206 &hashes
, &report_uri
));
207 EXPECT_FALSE(ParseHPKPHeader("max-aged=3488923" + backup_pin
, chain_hashes
,
208 &max_age
, &include_subdomains
, &hashes
,
210 EXPECT_FALSE(ParseHPKPHeader("max-aged=3488923; " + backup_pin
, chain_hashes
,
211 &max_age
, &include_subdomains
, &hashes
,
213 EXPECT_FALSE(ParseHPKPHeader(
214 "max-aged=3488923; " + backup_pin
+ ";" + backup_pin
, chain_hashes
,
215 &max_age
, &include_subdomains
, &hashes
, &report_uri
));
216 EXPECT_FALSE(ParseHPKPHeader("max-aged=3488923; " + good_pin
+ ";" + good_pin
,
217 chain_hashes
, &max_age
, &include_subdomains
,
218 &hashes
, &report_uri
));
219 EXPECT_FALSE(ParseHPKPHeader("max-aged=3488923; " + good_pin
, chain_hashes
,
220 &max_age
, &include_subdomains
, &hashes
,
222 EXPECT_FALSE(ParseHPKPHeader("max-age==3488923", chain_hashes
, &max_age
,
223 &include_subdomains
, &hashes
, &report_uri
));
224 EXPECT_FALSE(ParseHPKPHeader("amax-age=3488923", chain_hashes
, &max_age
,
225 &include_subdomains
, &hashes
, &report_uri
));
226 EXPECT_FALSE(ParseHPKPHeader("max-age=-3488923", chain_hashes
, &max_age
,
227 &include_subdomains
, &hashes
, &report_uri
));
228 EXPECT_FALSE(ParseHPKPHeader("max-age=3488923;", chain_hashes
, &max_age
,
229 &include_subdomains
, &hashes
, &report_uri
));
230 EXPECT_FALSE(ParseHPKPHeader("max-age=3488923 e", chain_hashes
, &max_age
,
231 &include_subdomains
, &hashes
, &report_uri
));
232 EXPECT_FALSE(ParseHPKPHeader("max-age=3488923 includesubdomain",
233 chain_hashes
, &max_age
, &include_subdomains
,
234 &hashes
, &report_uri
));
235 EXPECT_FALSE(ParseHPKPHeader(
236 "max-age=3488923 report-uri=\"http://foo.com\"", chain_hashes
,
237 &max_age
, &include_subdomains
, &hashes
, &report_uri
));
238 EXPECT_FALSE(ParseHPKPHeader("max-age=34889.23", chain_hashes
, &max_age
,
239 &include_subdomains
, &hashes
, &report_uri
));
240 EXPECT_FALSE(ParseHPKPHeader(
241 "max-age=243; " + good_pin_unquoted
+ ";" + backup_pin
, chain_hashes
,
242 &max_age
, &include_subdomains
, &hashes
, &report_uri
));
243 EXPECT_FALSE(ParseHPKPHeader(
244 "max-age=243; " + good_pin
+ ";" + backup_pin
+ ";report-uri=;",
245 chain_hashes
, &max_age
, &include_subdomains
, &hashes
, &report_uri
));
246 EXPECT_FALSE(ParseHPKPHeader("max-age=243; " + good_pin
+ ";" + backup_pin
+
247 ";report-uri=http://foo.com;",
248 chain_hashes
, &max_age
, &include_subdomains
,
249 &hashes
, &report_uri
));
250 EXPECT_FALSE(ParseHPKPHeader(
251 "max-age=243; " + good_pin
+ ";" + backup_pin
+ ";report-uri=''",
252 chain_hashes
, &max_age
, &include_subdomains
, &hashes
, &report_uri
));
254 // Test that the parser rejects misquoted strings.
255 EXPECT_FALSE(ParseHPKPHeader("max-age=999; " + backup_pin
+ "; " + good_pin
+
256 "; report-uri=\"http://foo;bar\'",
257 chain_hashes
, &max_age
, &include_subdomains
,
258 &hashes
, &report_uri
));
260 // Test that the parser rejects invalid report-uris.
261 EXPECT_FALSE(ParseHPKPHeader("max-age=999; " + backup_pin
+ "; " + good_pin
+
262 "; report-uri=\"foo;bar\'",
263 chain_hashes
, &max_age
, &include_subdomains
,
264 &hashes
, &report_uri
));
266 // Check the out args were not updated by checking the default
267 // values for its predictable fields.
268 EXPECT_EQ(0, max_age
.InSeconds());
269 EXPECT_EQ(hashes
.size(), (size_t)0);
272 TEST_F(HttpSecurityHeadersTest
, ValidSTSHeaders
) {
273 base::TimeDelta max_age
;
274 base::TimeDelta expect_max_age
;
275 bool include_subdomains
= false;
277 EXPECT_TRUE(ParseHSTSHeader("max-age=243", &max_age
,
278 &include_subdomains
));
279 expect_max_age
= base::TimeDelta::FromSeconds(243);
280 EXPECT_EQ(expect_max_age
, max_age
);
281 EXPECT_FALSE(include_subdomains
);
283 EXPECT_TRUE(ParseHSTSHeader("max-age=3488923;", &max_age
,
284 &include_subdomains
));
286 EXPECT_TRUE(ParseHSTSHeader(" Max-agE = 567", &max_age
,
287 &include_subdomains
));
288 expect_max_age
= base::TimeDelta::FromSeconds(567);
289 EXPECT_EQ(expect_max_age
, max_age
);
290 EXPECT_FALSE(include_subdomains
);
292 EXPECT_TRUE(ParseHSTSHeader(" mAx-aGe = 890 ", &max_age
,
293 &include_subdomains
));
294 expect_max_age
= base::TimeDelta::FromSeconds(890);
295 EXPECT_EQ(expect_max_age
, max_age
);
296 EXPECT_FALSE(include_subdomains
);
298 EXPECT_TRUE(ParseHSTSHeader("max-age=123;incLudesUbdOmains", &max_age
,
299 &include_subdomains
));
300 expect_max_age
= base::TimeDelta::FromSeconds(123);
301 EXPECT_EQ(expect_max_age
, max_age
);
302 EXPECT_TRUE(include_subdomains
);
304 EXPECT_TRUE(ParseHSTSHeader("incLudesUbdOmains; max-age=123", &max_age
,
305 &include_subdomains
));
306 expect_max_age
= base::TimeDelta::FromSeconds(123);
307 EXPECT_EQ(expect_max_age
, max_age
);
308 EXPECT_TRUE(include_subdomains
);
310 EXPECT_TRUE(ParseHSTSHeader(" incLudesUbdOmains; max-age=123",
311 &max_age
, &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 " incLudesUbdOmains; max-age=123; pumpkin=kitten", &max_age
,
318 &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(
324 " pumpkin=894; incLudesUbdOmains; max-age=123 ", &max_age
,
325 &include_subdomains
));
326 expect_max_age
= base::TimeDelta::FromSeconds(123);
327 EXPECT_EQ(expect_max_age
, max_age
);
328 EXPECT_TRUE(include_subdomains
);
330 EXPECT_TRUE(ParseHSTSHeader(
331 " pumpkin; incLudesUbdOmains; max-age=123 ", &max_age
,
332 &include_subdomains
));
333 expect_max_age
= base::TimeDelta::FromSeconds(123);
334 EXPECT_EQ(expect_max_age
, max_age
);
335 EXPECT_TRUE(include_subdomains
);
337 EXPECT_TRUE(ParseHSTSHeader(
338 " pumpkin; incLudesUbdOmains; max-age=\"123\" ", &max_age
,
339 &include_subdomains
));
340 expect_max_age
= base::TimeDelta::FromSeconds(123);
341 EXPECT_EQ(expect_max_age
, max_age
);
342 EXPECT_TRUE(include_subdomains
);
344 EXPECT_TRUE(ParseHSTSHeader(
345 "animal=\"squirrel; distinguished\"; incLudesUbdOmains; max-age=123",
346 &max_age
, &include_subdomains
));
347 expect_max_age
= base::TimeDelta::FromSeconds(123);
348 EXPECT_EQ(expect_max_age
, max_age
);
349 EXPECT_TRUE(include_subdomains
);
351 EXPECT_TRUE(ParseHSTSHeader("max-age=394082; incLudesUbdOmains",
352 &max_age
, &include_subdomains
));
353 expect_max_age
= base::TimeDelta::FromSeconds(394082);
354 EXPECT_EQ(expect_max_age
, max_age
);
355 EXPECT_TRUE(include_subdomains
);
357 EXPECT_TRUE(ParseHSTSHeader(
358 "max-age=39408299 ;incLudesUbdOmains", &max_age
,
359 &include_subdomains
));
360 expect_max_age
= base::TimeDelta::FromSeconds(
361 std::min(kMaxHSTSAgeSecs
, static_cast<int64
>(INT64_C(39408299))));
362 EXPECT_EQ(expect_max_age
, max_age
);
363 EXPECT_TRUE(include_subdomains
);
365 EXPECT_TRUE(ParseHSTSHeader(
366 "max-age=394082038 ; incLudesUbdOmains", &max_age
,
367 &include_subdomains
));
368 expect_max_age
= base::TimeDelta::FromSeconds(
369 std::min(kMaxHSTSAgeSecs
, static_cast<int64
>(INT64_C(394082038))));
370 EXPECT_EQ(expect_max_age
, max_age
);
371 EXPECT_TRUE(include_subdomains
);
373 EXPECT_TRUE(ParseHSTSHeader(
374 "max-age=394082038 ; incLudesUbdOmains;", &max_age
,
375 &include_subdomains
));
376 expect_max_age
= base::TimeDelta::FromSeconds(
377 std::min(kMaxHSTSAgeSecs
, static_cast<int64
>(INT64_C(394082038))));
378 EXPECT_EQ(expect_max_age
, max_age
);
379 EXPECT_TRUE(include_subdomains
);
381 EXPECT_TRUE(ParseHSTSHeader(
382 ";; max-age=394082038 ; incLudesUbdOmains; ;", &max_age
,
383 &include_subdomains
));
384 expect_max_age
= base::TimeDelta::FromSeconds(
385 std::min(kMaxHSTSAgeSecs
, static_cast<int64
>(INT64_C(394082038))));
386 EXPECT_EQ(expect_max_age
, max_age
);
387 EXPECT_TRUE(include_subdomains
);
389 EXPECT_TRUE(ParseHSTSHeader(
390 ";; max-age=394082038 ;", &max_age
,
391 &include_subdomains
));
392 expect_max_age
= base::TimeDelta::FromSeconds(
393 std::min(kMaxHSTSAgeSecs
, static_cast<int64
>(INT64_C(394082038))));
394 EXPECT_EQ(expect_max_age
, max_age
);
395 EXPECT_FALSE(include_subdomains
);
397 EXPECT_TRUE(ParseHSTSHeader(
398 ";; ; ; max-age=394082038;;; includeSubdomains ;; ;", &max_age
,
399 &include_subdomains
));
400 expect_max_age
= base::TimeDelta::FromSeconds(
401 std::min(kMaxHSTSAgeSecs
, static_cast<int64
>(INT64_C(394082038))));
402 EXPECT_EQ(expect_max_age
, max_age
);
403 EXPECT_TRUE(include_subdomains
);
405 EXPECT_TRUE(ParseHSTSHeader(
406 "incLudesUbdOmains ; max-age=394082038 ;;", &max_age
,
407 &include_subdomains
));
408 expect_max_age
= base::TimeDelta::FromSeconds(
409 std::min(kMaxHSTSAgeSecs
, static_cast<int64
>(INT64_C(394082038))));
410 EXPECT_EQ(expect_max_age
, max_age
);
411 EXPECT_TRUE(include_subdomains
);
413 EXPECT_TRUE(ParseHSTSHeader(
414 " max-age=0 ; incLudesUbdOmains ", &max_age
,
415 &include_subdomains
));
416 expect_max_age
= base::TimeDelta::FromSeconds(0);
417 EXPECT_EQ(expect_max_age
, max_age
);
418 EXPECT_TRUE(include_subdomains
);
420 EXPECT_TRUE(ParseHSTSHeader(
421 " max-age=999999999999999999999999999999999999999999999 ;"
422 " incLudesUbdOmains ", &max_age
, &include_subdomains
));
423 expect_max_age
= base::TimeDelta::FromSeconds(
425 EXPECT_EQ(expect_max_age
, max_age
);
426 EXPECT_TRUE(include_subdomains
);
429 static void TestValidPKPHeaders(HashValueTag tag
) {
430 base::TimeDelta max_age
;
431 base::TimeDelta expect_max_age
;
432 bool include_subdomains
;
433 HashValueVector hashes
;
434 HashValueVector chain_hashes
;
435 GURL expect_report_uri
;
438 // Set some fake "chain" hashes into chain_hashes
439 chain_hashes
.push_back(GetTestHashValue(1, tag
));
440 chain_hashes
.push_back(GetTestHashValue(2, tag
));
441 chain_hashes
.push_back(GetTestHashValue(3, tag
));
443 // The good pin must be in the chain, the backup pin must not be
444 std::string good_pin
= GetTestPin(2, tag
);
445 std::string good_pin2
= GetTestPin(3, tag
);
446 std::string backup_pin
= GetTestPin(4, tag
);
448 EXPECT_TRUE(ParseHPKPHeader("max-age=243; " + good_pin
+ ";" + backup_pin
,
449 chain_hashes
, &max_age
, &include_subdomains
,
450 &hashes
, &report_uri
));
451 expect_max_age
= base::TimeDelta::FromSeconds(243);
452 EXPECT_EQ(expect_max_age
, max_age
);
453 EXPECT_FALSE(include_subdomains
);
454 EXPECT_TRUE(report_uri
.is_empty());
456 EXPECT_TRUE(ParseHPKPHeader("max-age=243; " + good_pin
+ ";" + backup_pin
+
457 "; report-uri= \"http://example.test/foo\"",
458 chain_hashes
, &max_age
, &include_subdomains
,
459 &hashes
, &report_uri
));
460 expect_max_age
= base::TimeDelta::FromSeconds(243);
461 expect_report_uri
= GURL("http://example.test/foo");
462 EXPECT_EQ(expect_max_age
, max_age
);
463 EXPECT_FALSE(include_subdomains
);
464 EXPECT_EQ(expect_report_uri
, report_uri
);
466 EXPECT_TRUE(ParseHPKPHeader(
467 " " + good_pin
+ "; " + backup_pin
+
468 " ; Max-agE = 567; repOrT-URi = \"http://example.test/foo\"",
469 chain_hashes
, &max_age
, &include_subdomains
, &hashes
, &report_uri
));
470 expect_max_age
= base::TimeDelta::FromSeconds(567);
471 expect_report_uri
= GURL("http://example.test/foo");
472 EXPECT_EQ(expect_max_age
, max_age
);
473 EXPECT_FALSE(include_subdomains
);
474 EXPECT_EQ(expect_report_uri
, report_uri
);
476 EXPECT_TRUE(ParseHPKPHeader("includeSubDOMAINS;" + good_pin
+ ";" +
477 backup_pin
+ " ; mAx-aGe = 890 ",
478 chain_hashes
, &max_age
, &include_subdomains
,
479 &hashes
, &report_uri
));
480 expect_max_age
= base::TimeDelta::FromSeconds(890);
481 EXPECT_EQ(expect_max_age
, max_age
);
482 EXPECT_TRUE(include_subdomains
);
484 EXPECT_TRUE(ParseHPKPHeader(
485 good_pin
+ ";" + backup_pin
+ "; max-age=123;IGNORED;", chain_hashes
,
486 &max_age
, &include_subdomains
, &hashes
, &report_uri
));
487 expect_max_age
= base::TimeDelta::FromSeconds(123);
488 EXPECT_EQ(expect_max_age
, max_age
);
489 EXPECT_FALSE(include_subdomains
);
491 EXPECT_TRUE(ParseHPKPHeader(
492 "max-age=394082;" + backup_pin
+ ";" + good_pin
+ "; ", chain_hashes
,
493 &max_age
, &include_subdomains
, &hashes
, &report_uri
));
494 expect_max_age
= base::TimeDelta::FromSeconds(394082);
495 EXPECT_EQ(expect_max_age
, max_age
);
496 EXPECT_FALSE(include_subdomains
);
498 EXPECT_TRUE(ParseHPKPHeader(
499 "max-age=39408299 ;" + backup_pin
+ ";" + good_pin
+ "; ", chain_hashes
,
500 &max_age
, &include_subdomains
, &hashes
, &report_uri
));
501 expect_max_age
= base::TimeDelta::FromSeconds(
502 std::min(kMaxHSTSAgeSecs
, static_cast<int64
>(INT64_C(39408299))));
503 EXPECT_EQ(expect_max_age
, max_age
);
504 EXPECT_FALSE(include_subdomains
);
506 EXPECT_TRUE(ParseHPKPHeader(
507 "max-age=39408038 ; cybers=39408038 ; includeSubdomains; " +
508 good_pin
+ ";" + backup_pin
+ "; ",
509 chain_hashes
, &max_age
, &include_subdomains
, &hashes
, &report_uri
));
510 expect_max_age
= base::TimeDelta::FromSeconds(
511 std::min(kMaxHSTSAgeSecs
, static_cast<int64
>(INT64_C(394082038))));
512 EXPECT_EQ(expect_max_age
, max_age
);
513 EXPECT_TRUE(include_subdomains
);
515 EXPECT_TRUE(ParseHPKPHeader(" max-age=0 ; " + good_pin
+ ";" + backup_pin
,
516 chain_hashes
, &max_age
, &include_subdomains
,
517 &hashes
, &report_uri
));
518 expect_max_age
= base::TimeDelta::FromSeconds(0);
519 EXPECT_EQ(expect_max_age
, max_age
);
520 EXPECT_FALSE(include_subdomains
);
522 EXPECT_TRUE(ParseHPKPHeader(
523 " max-age=0 ; includeSubdomains; " + good_pin
+ ";" + backup_pin
,
524 chain_hashes
, &max_age
, &include_subdomains
, &hashes
, &report_uri
));
525 expect_max_age
= base::TimeDelta::FromSeconds(0);
526 EXPECT_EQ(expect_max_age
, max_age
);
527 EXPECT_TRUE(include_subdomains
);
529 EXPECT_TRUE(ParseHPKPHeader(
530 " max-age=999999999999999999999999999999999999999999999 ; " +
531 backup_pin
+ ";" + good_pin
+ "; ",
532 chain_hashes
, &max_age
, &include_subdomains
, &hashes
, &report_uri
));
533 expect_max_age
= base::TimeDelta::FromSeconds(kMaxHSTSAgeSecs
);
534 EXPECT_EQ(expect_max_age
, max_age
);
535 EXPECT_FALSE(include_subdomains
);
537 EXPECT_TRUE(ParseHPKPHeader(
538 " max-age=999999999999999999999999999999999999999999999 ; " +
539 backup_pin
+ ";" + good_pin
+
540 "; report-uri=\"http://example.test/foo\"",
541 chain_hashes
, &max_age
, &include_subdomains
, &hashes
, &report_uri
));
542 expect_max_age
= base::TimeDelta::FromSeconds(kMaxHSTSAgeSecs
);
543 expect_report_uri
= GURL("http://example.test/foo");
544 EXPECT_EQ(expect_max_age
, max_age
);
545 EXPECT_FALSE(include_subdomains
);
546 EXPECT_EQ(expect_report_uri
, report_uri
);
548 // Test that parsing a different header resets the hashes.
550 EXPECT_TRUE(ParseHPKPHeader(
551 " max-age=999; " + backup_pin
+ ";" + good_pin
+ "; ", chain_hashes
,
552 &max_age
, &include_subdomains
, &hashes
, &report_uri
));
553 EXPECT_EQ(2u, hashes
.size());
554 EXPECT_TRUE(ParseHPKPHeader(
555 " max-age=999; " + backup_pin
+ ";" + good_pin2
+ "; ", chain_hashes
,
556 &max_age
, &include_subdomains
, &hashes
, &report_uri
));
557 EXPECT_EQ(2u, hashes
.size());
559 // Test that the parser correctly parses an unencoded ';' inside a
560 // quoted report-uri.
561 EXPECT_TRUE(ParseHPKPHeader("max-age=999; " + backup_pin
+ "; " + good_pin
+
562 "; report-uri=\"http://foo.com/?;bar\"",
563 chain_hashes
, &max_age
, &include_subdomains
,
564 &hashes
, &report_uri
));
565 expect_max_age
= base::TimeDelta::FromSeconds(999);
566 expect_report_uri
= GURL("http://foo.com/?;bar");
567 EXPECT_EQ(expect_max_age
, max_age
);
568 EXPECT_FALSE(include_subdomains
);
569 EXPECT_EQ(expect_report_uri
, report_uri
);
571 // Test that the parser correctly parses a report-uri with a >0x7f
573 std::string uri
= "http://foo.com/";
575 expect_report_uri
= GURL(uri
);
576 EXPECT_TRUE(ParseHPKPHeader("max-age=999; " + backup_pin
+ "; " + good_pin
+
577 "; report-uri=\"" + uri
+ "\"",
578 chain_hashes
, &max_age
, &include_subdomains
,
579 &hashes
, &report_uri
));
580 expect_max_age
= base::TimeDelta::FromSeconds(999);
581 EXPECT_EQ(expect_max_age
, max_age
);
582 EXPECT_FALSE(include_subdomains
);
583 EXPECT_EQ(expect_report_uri
, report_uri
);
585 // Test that the parser allows quoted max-age values.
586 EXPECT_TRUE(ParseHPKPHeader("max-age='999'; " + backup_pin
+ "; " + good_pin
,
587 chain_hashes
, &max_age
, &include_subdomains
,
588 &hashes
, &report_uri
));
589 expect_max_age
= base::TimeDelta::FromSeconds(999);
590 EXPECT_EQ(expect_max_age
, max_age
);
591 EXPECT_FALSE(include_subdomains
);
593 // Test that the parser handles escaped values.
594 expect_report_uri
= GURL("http://foo.com'a");
595 EXPECT_TRUE(ParseHPKPHeader("max-age=999; " + backup_pin
+ "; " + good_pin
+
596 "; report-uri='http://foo.com\\'\\a'",
597 chain_hashes
, &max_age
, &include_subdomains
,
598 &hashes
, &report_uri
));
599 expect_max_age
= base::TimeDelta::FromSeconds(999);
600 EXPECT_EQ(expect_max_age
, max_age
);
601 EXPECT_FALSE(include_subdomains
);
602 EXPECT_EQ(expect_report_uri
, report_uri
);
605 TEST_F(HttpSecurityHeadersTest
, BogusPinsHeadersSHA1
) {
606 TestBogusPinsHeaders(HASH_VALUE_SHA1
);
609 TEST_F(HttpSecurityHeadersTest
, BogusPinsHeadersSHA256
) {
610 TestBogusPinsHeaders(HASH_VALUE_SHA256
);
613 TEST_F(HttpSecurityHeadersTest
, ValidPKPHeadersSHA1
) {
614 TestValidPKPHeaders(HASH_VALUE_SHA1
);
617 TEST_F(HttpSecurityHeadersTest
, ValidPKPHeadersSHA256
) {
618 TestValidPKPHeaders(HASH_VALUE_SHA256
);
621 TEST_F(HttpSecurityHeadersTest
, UpdateDynamicPKPOnly
) {
622 TransportSecurityState state
;
623 TransportSecurityState::STSState static_sts_state
;
624 TransportSecurityState::PKPState static_pkp_state
;
626 // docs.google.com has preloaded pins.
627 std::string domain
= "docs.google.com";
628 state
.enable_static_pins_
= true;
630 state
.GetStaticDomainState(domain
, &static_sts_state
, &static_pkp_state
));
631 EXPECT_GT(static_pkp_state
.spki_hashes
.size(), 1UL);
632 HashValueVector saved_hashes
= static_pkp_state
.spki_hashes
;
634 // Add a header, which should only update the dynamic state.
635 HashValue good_hash
= GetTestHashValue(1, HASH_VALUE_SHA1
);
636 HashValue backup_hash
= GetTestHashValue(2, HASH_VALUE_SHA1
);
637 std::string good_pin
= GetTestPin(1, HASH_VALUE_SHA1
);
638 std::string backup_pin
= GetTestPin(2, HASH_VALUE_SHA1
);
639 GURL
report_uri("http://google.com");
640 std::string header
= "max-age = 10000; " + good_pin
+ "; " + backup_pin
+
641 ";report-uri=\"" + report_uri
.spec() + "\"";
643 // Construct a fake SSLInfo that will pass AddHPKPHeader's checks.
645 ssl_info
.public_key_hashes
.push_back(good_hash
);
646 ssl_info
.public_key_hashes
.push_back(saved_hashes
[0]);
647 EXPECT_TRUE(state
.AddHPKPHeader(domain
, header
, ssl_info
));
649 // Expect the static state to remain unchanged.
650 TransportSecurityState::STSState new_static_sts_state
;
651 TransportSecurityState::PKPState new_static_pkp_state
;
652 EXPECT_TRUE(state
.GetStaticDomainState(domain
, &new_static_sts_state
,
653 &new_static_pkp_state
));
654 for (size_t i
= 0; i
< saved_hashes
.size(); ++i
) {
656 HashValuesEqual(saved_hashes
[i
])(new_static_pkp_state
.spki_hashes
[i
]));
659 // Expect the dynamic state to reflect the header.
660 TransportSecurityState::PKPState dynamic_pkp_state
;
661 EXPECT_TRUE(state
.GetDynamicPKPState(domain
, &dynamic_pkp_state
));
662 EXPECT_EQ(2UL, dynamic_pkp_state
.spki_hashes
.size());
663 EXPECT_EQ(report_uri
, dynamic_pkp_state
.report_uri
);
665 HashValueVector::const_iterator hash
= std::find_if(
666 dynamic_pkp_state
.spki_hashes
.begin(),
667 dynamic_pkp_state
.spki_hashes
.end(), HashValuesEqual(good_hash
));
668 EXPECT_NE(dynamic_pkp_state
.spki_hashes
.end(), hash
);
670 hash
= std::find_if(dynamic_pkp_state
.spki_hashes
.begin(),
671 dynamic_pkp_state
.spki_hashes
.end(),
672 HashValuesEqual(backup_hash
));
673 EXPECT_NE(dynamic_pkp_state
.spki_hashes
.end(), hash
);
675 // Expect the overall state to reflect the header, too.
676 EXPECT_TRUE(state
.HasPublicKeyPins(domain
));
677 HashValueVector hashes
;
678 hashes
.push_back(good_hash
);
679 std::string failure_log
;
680 const bool is_issued_by_known_root
= true;
681 EXPECT_TRUE(state
.CheckPublicKeyPins(
682 domain
, is_issued_by_known_root
, hashes
, &failure_log
));
684 TransportSecurityState::PKPState new_dynamic_pkp_state
;
685 EXPECT_TRUE(state
.GetDynamicPKPState(domain
, &new_dynamic_pkp_state
));
686 EXPECT_EQ(2UL, new_dynamic_pkp_state
.spki_hashes
.size());
687 EXPECT_EQ(report_uri
, new_dynamic_pkp_state
.report_uri
);
689 hash
= std::find_if(new_dynamic_pkp_state
.spki_hashes
.begin(),
690 new_dynamic_pkp_state
.spki_hashes
.end(),
691 HashValuesEqual(good_hash
));
692 EXPECT_NE(new_dynamic_pkp_state
.spki_hashes
.end(), hash
);
694 hash
= std::find_if(new_dynamic_pkp_state
.spki_hashes
.begin(),
695 new_dynamic_pkp_state
.spki_hashes
.end(),
696 HashValuesEqual(backup_hash
));
697 EXPECT_NE(new_dynamic_pkp_state
.spki_hashes
.end(), hash
);
700 TEST_F(HttpSecurityHeadersTest
, UpdateDynamicPKPMaxAge0
) {
701 TransportSecurityState state
;
702 TransportSecurityState::STSState static_sts_state
;
703 TransportSecurityState::PKPState static_pkp_state
;
705 // docs.google.com has preloaded pins.
706 std::string domain
= "docs.google.com";
707 state
.enable_static_pins_
= true;
709 state
.GetStaticDomainState(domain
, &static_sts_state
, &static_pkp_state
));
710 EXPECT_GT(static_pkp_state
.spki_hashes
.size(), 1UL);
711 HashValueVector saved_hashes
= static_pkp_state
.spki_hashes
;
713 // Add a header, which should only update the dynamic state.
714 HashValue good_hash
= GetTestHashValue(1, HASH_VALUE_SHA1
);
715 std::string good_pin
= GetTestPin(1, HASH_VALUE_SHA1
);
716 std::string backup_pin
= GetTestPin(2, HASH_VALUE_SHA1
);
717 std::string header
= "max-age = 10000; " + good_pin
+ "; " + backup_pin
;
719 // Construct a fake SSLInfo that will pass AddHPKPHeader's checks.
721 ssl_info
.public_key_hashes
.push_back(good_hash
);
722 ssl_info
.public_key_hashes
.push_back(saved_hashes
[0]);
723 EXPECT_TRUE(state
.AddHPKPHeader(domain
, header
, ssl_info
));
725 // Expect the static state to remain unchanged.
726 TransportSecurityState::STSState new_static_sts_state
;
727 TransportSecurityState::PKPState new_static_pkp_state
;
728 EXPECT_TRUE(state
.GetStaticDomainState(domain
, &new_static_sts_state
,
729 &new_static_pkp_state
));
730 EXPECT_EQ(saved_hashes
.size(), new_static_pkp_state
.spki_hashes
.size());
731 for (size_t i
= 0; i
< saved_hashes
.size(); ++i
) {
733 HashValuesEqual(saved_hashes
[i
])(new_static_pkp_state
.spki_hashes
[i
]));
736 // Expect the dynamic state to have pins.
737 TransportSecurityState::PKPState new_dynamic_pkp_state
;
738 EXPECT_TRUE(state
.GetDynamicPKPState(domain
, &new_dynamic_pkp_state
));
739 EXPECT_EQ(2UL, new_dynamic_pkp_state
.spki_hashes
.size());
740 EXPECT_TRUE(new_dynamic_pkp_state
.HasPublicKeyPins());
742 // Now set another header with max-age=0, and check that the pins are
743 // cleared in the dynamic state only.
744 header
= "max-age = 0; " + good_pin
+ "; " + backup_pin
;
745 EXPECT_TRUE(state
.AddHPKPHeader(domain
, header
, ssl_info
));
747 // Expect the static state to remain unchanged.
748 TransportSecurityState::PKPState new_static_pkp_state2
;
749 EXPECT_TRUE(state
.GetStaticDomainState(domain
, &static_sts_state
,
750 &new_static_pkp_state2
));
751 EXPECT_EQ(saved_hashes
.size(), new_static_pkp_state2
.spki_hashes
.size());
752 for (size_t i
= 0; i
< saved_hashes
.size(); ++i
) {
754 HashValuesEqual(saved_hashes
[i
])(new_static_pkp_state2
.spki_hashes
[i
]));
757 // Expect the dynamic pins to be gone.
758 TransportSecurityState::PKPState new_dynamic_pkp_state2
;
759 EXPECT_FALSE(state
.GetDynamicPKPState(domain
, &new_dynamic_pkp_state2
));
761 // Expect the exact-matching static policy to continue to apply, even
762 // though dynamic policy has been removed. (This policy may change in the
763 // future, in which case this test must be updated.)
764 EXPECT_TRUE(state
.HasPublicKeyPins(domain
));
765 EXPECT_TRUE(state
.ShouldSSLErrorsBeFatal(domain
));
766 std::string failure_log
;
768 // Damage the hashes to cause a pin validation failure.
769 new_static_pkp_state2
.spki_hashes
[0].data()[0] ^= 0x80;
770 new_static_pkp_state2
.spki_hashes
[1].data()[0] ^= 0x80;
771 new_static_pkp_state2
.spki_hashes
[2].data()[0] ^= 0x80;
773 const bool is_issued_by_known_root
= true;
774 EXPECT_FALSE(state
.CheckPublicKeyPins(domain
, is_issued_by_known_root
,
775 new_static_pkp_state2
.spki_hashes
,
777 EXPECT_NE(0UL, failure_log
.length());
780 // Tests that when a static HSTS and a static HPKP entry are present, adding a
781 // dynamic HSTS header does not clobber the static HPKP entry. Further, adding a
782 // dynamic HPKP entry could not affect the HSTS entry for the site.
783 TEST_F(HttpSecurityHeadersTest
, NoClobberPins
) {
784 TransportSecurityState state
;
785 TransportSecurityState::STSState sts_state
;
786 TransportSecurityState::PKPState pkp_state
;
788 // accounts.google.com has preloaded pins.
789 std::string domain
= "accounts.google.com";
790 state
.enable_static_pins_
= true;
792 // Retrieve the static STS and PKP states as it is by default, including its
794 EXPECT_TRUE(state
.GetStaticDomainState(domain
, &sts_state
, &pkp_state
));
795 HashValueVector saved_hashes
= pkp_state
.spki_hashes
;
796 EXPECT_TRUE(sts_state
.ShouldUpgradeToSSL());
797 EXPECT_TRUE(pkp_state
.HasPublicKeyPins());
798 EXPECT_TRUE(state
.ShouldUpgradeToSSL(domain
));
799 EXPECT_TRUE(state
.HasPublicKeyPins(domain
));
801 // Add a dynamic HSTS header. CheckPublicKeyPins should still pass when given
802 // the original |saved_hashes|, indicating that the static PKP data is still
803 // configured for the domain.
804 EXPECT_TRUE(state
.AddHSTSHeader(domain
, "includesubdomains; max-age=10000"));
805 EXPECT_TRUE(state
.ShouldUpgradeToSSL(domain
));
806 std::string failure_log
;
807 const bool is_issued_by_known_root
= true;
808 EXPECT_TRUE(state
.CheckPublicKeyPins(domain
,
809 is_issued_by_known_root
,
813 // Add an HPKP header, which should only update the dynamic state.
814 HashValue good_hash
= GetTestHashValue(1, HASH_VALUE_SHA1
);
815 std::string good_pin
= GetTestPin(1, HASH_VALUE_SHA1
);
816 std::string backup_pin
= GetTestPin(2, HASH_VALUE_SHA1
);
817 std::string header
= "max-age = 10000; " + good_pin
+ "; " + backup_pin
;
819 // Construct a fake SSLInfo that will pass AddHPKPHeader's checks.
821 ssl_info
.public_key_hashes
.push_back(good_hash
);
822 ssl_info
.public_key_hashes
.push_back(saved_hashes
[0]);
823 EXPECT_TRUE(state
.AddHPKPHeader(domain
, header
, ssl_info
));
825 EXPECT_TRUE(state
.AddHPKPHeader(domain
, header
, ssl_info
));
826 // HSTS should still be configured for this domain.
827 EXPECT_TRUE(sts_state
.ShouldUpgradeToSSL());
828 EXPECT_TRUE(state
.ShouldUpgradeToSSL(domain
));
829 // The dynamic pins, which do not match |saved_hashes|, should take
830 // precedence over the static pins and cause the check to fail.
831 EXPECT_FALSE(state
.CheckPublicKeyPins(domain
,
832 is_issued_by_known_root
,
837 // Tests that seeing an invalid HPKP header leaves the existing one alone.
838 TEST_F(HttpSecurityHeadersTest
, IgnoreInvalidHeaders
) {
839 TransportSecurityState state
;
841 HashValue good_hash
= GetTestHashValue(1, HASH_VALUE_SHA256
);
842 std::string good_pin
= GetTestPin(1, HASH_VALUE_SHA256
);
843 std::string bad_pin
= GetTestPin(2, HASH_VALUE_SHA256
);
844 std::string backup_pin
= GetTestPin(3, HASH_VALUE_SHA256
);
847 ssl_info
.public_key_hashes
.push_back(good_hash
);
849 // Add a valid HPKP header.
850 EXPECT_TRUE(state
.AddHPKPHeader(
851 "example.com", "max-age = 10000; " + good_pin
+ "; " + backup_pin
,
854 // Check the insertion was valid.
855 EXPECT_TRUE(state
.HasPublicKeyPins("example.com"));
856 std::string failure_log
;
857 bool is_issued_by_known_root
= true;
858 EXPECT_TRUE(state
.CheckPublicKeyPins("example.com", is_issued_by_known_root
,
859 ssl_info
.public_key_hashes
,
862 // Now assert an invalid one. This should fail.
863 EXPECT_FALSE(state
.AddHPKPHeader(
864 "example.com", "max-age = 10000; " + bad_pin
+ "; " + backup_pin
,
867 // The old pins must still exist.
868 EXPECT_TRUE(state
.HasPublicKeyPins("example.com"));
869 EXPECT_TRUE(state
.CheckPublicKeyPins("example.com", is_issued_by_known_root
,
870 ssl_info
.public_key_hashes
,