Allow only one bookmark to be added for multiple fast starring
[chromium-blink-merge.git] / net / http / http_security_headers_unittest.cc
blobf9e3e18636c6184afb0f0f589b4f79016befe767
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.
5 #include <stdint.h>
6 #include <algorithm>
8 #include "base/base64.h"
9 #include "base/sha1.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"
21 namespace net {
23 namespace {
25 HashValue GetTestHashValue(uint8 label, HashValueTag tag) {
26 HashValue hash_value(tag);
27 memset(hash_value.data(), label, hash_value.size());
28 return hash_value;
31 std::string GetTestPinImpl(uint8 label, HashValueTag tag, bool quoted) {
32 HashValue hash_value = GetTestHashValue(label, tag);
33 std::string base64;
34 base::Base64Encode(base::StringPiece(
35 reinterpret_cast<char*>(hash_value.data()), hash_value.size()), &base64);
37 std::string ret;
38 switch (hash_value.tag) {
39 case HASH_VALUE_SHA1:
40 ret = "pin-sha1=";
41 break;
42 case HASH_VALUE_SHA256:
43 ret = "pin-sha256=";
44 break;
45 default:
46 NOTREACHED() << "Unknown HashValueTag " << hash_value.tag;
47 return std::string("ERROR");
49 if (quoted)
50 ret += '\"';
51 ret += base64;
52 if (quoted)
53 ret += '\"';
54 return ret;
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);
67 // Parses the given header |value| as both a Public-Key-Pins-Report-Only
68 // and Public-Key-Pins header. Returns true if the value parses
69 // successfully for both header types, and if the parsed hashes and
70 // report_uri match for both header types.
71 bool ParseAsHPKPHeader(const std::string& value,
72 const HashValueVector& chain_hashes,
73 base::TimeDelta* max_age,
74 bool* include_subdomains,
75 HashValueVector* hashes,
76 GURL* report_uri) {
77 GURL report_only_uri;
78 bool report_only_include_subdomains;
79 HashValueVector report_only_hashes;
80 if (!ParseHPKPReportOnlyHeader(value, &report_only_include_subdomains,
81 &report_only_hashes, &report_only_uri)) {
82 return false;
85 bool result = ParseHPKPHeader(value, chain_hashes, max_age,
86 include_subdomains, hashes, report_uri);
87 if (!result || report_only_include_subdomains != *include_subdomains ||
88 report_only_uri != *report_uri ||
89 report_only_hashes.size() != hashes->size()) {
90 return false;
93 for (size_t i = 0; i < report_only_hashes.size(); i++) {
94 if (!(*hashes)[i].Equals(report_only_hashes[i]))
95 return false;
98 return true;
101 class HttpSecurityHeadersTest : public testing::Test {
105 TEST_F(HttpSecurityHeadersTest, BogusHeaders) {
106 base::TimeDelta max_age;
107 bool include_subdomains = false;
109 EXPECT_FALSE(
110 ParseHSTSHeader(std::string(), &max_age, &include_subdomains));
111 EXPECT_FALSE(ParseHSTSHeader(" ", &max_age, &include_subdomains));
112 EXPECT_FALSE(ParseHSTSHeader("abc", &max_age, &include_subdomains));
113 EXPECT_FALSE(ParseHSTSHeader(" abc", &max_age, &include_subdomains));
114 EXPECT_FALSE(ParseHSTSHeader(" abc ", &max_age, &include_subdomains));
115 EXPECT_FALSE(ParseHSTSHeader("max-age", &max_age, &include_subdomains));
116 EXPECT_FALSE(ParseHSTSHeader(" max-age", &max_age,
117 &include_subdomains));
118 EXPECT_FALSE(ParseHSTSHeader(" max-age ", &max_age,
119 &include_subdomains));
120 EXPECT_FALSE(ParseHSTSHeader("max-age=", &max_age, &include_subdomains));
121 EXPECT_FALSE(ParseHSTSHeader(" max-age=", &max_age,
122 &include_subdomains));
123 EXPECT_FALSE(ParseHSTSHeader(" max-age =", &max_age,
124 &include_subdomains));
125 EXPECT_FALSE(ParseHSTSHeader(" max-age= ", &max_age,
126 &include_subdomains));
127 EXPECT_FALSE(ParseHSTSHeader(" max-age = ", &max_age,
128 &include_subdomains));
129 EXPECT_FALSE(ParseHSTSHeader(" max-age = xy", &max_age,
130 &include_subdomains));
131 EXPECT_FALSE(ParseHSTSHeader(" max-age = 3488a923", &max_age,
132 &include_subdomains));
133 EXPECT_FALSE(ParseHSTSHeader("max-age=3488a923 ", &max_age,
134 &include_subdomains));
135 EXPECT_FALSE(ParseHSTSHeader("max-ag=3488923", &max_age,
136 &include_subdomains));
137 EXPECT_FALSE(ParseHSTSHeader("max-aged=3488923", &max_age,
138 &include_subdomains));
139 EXPECT_FALSE(ParseHSTSHeader("max-age==3488923", &max_age,
140 &include_subdomains));
141 EXPECT_FALSE(ParseHSTSHeader("amax-age=3488923", &max_age,
142 &include_subdomains));
143 EXPECT_FALSE(ParseHSTSHeader("max-age=-3488923", &max_age,
144 &include_subdomains));
145 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923 e", &max_age,
146 &include_subdomains));
147 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923 includesubdomain",
148 &max_age, &include_subdomains));
149 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923includesubdomains",
150 &max_age, &include_subdomains));
151 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923=includesubdomains",
152 &max_age, &include_subdomains));
153 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923 includesubdomainx",
154 &max_age, &include_subdomains));
155 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923 includesubdomain=",
156 &max_age, &include_subdomains));
157 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923 includesubdomain=true",
158 &max_age, &include_subdomains));
159 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923 includesubdomainsx",
160 &max_age, &include_subdomains));
161 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923 includesubdomains x",
162 &max_age, &include_subdomains));
163 EXPECT_FALSE(ParseHSTSHeader("max-age=34889.23 includesubdomains",
164 &max_age, &include_subdomains));
165 EXPECT_FALSE(ParseHSTSHeader("max-age=34889 includesubdomains",
166 &max_age, &include_subdomains));
167 EXPECT_FALSE(ParseHSTSHeader(";;;; ;;;",
168 &max_age, &include_subdomains));
169 EXPECT_FALSE(ParseHSTSHeader(";;;; includeSubDomains;;;",
170 &max_age, &include_subdomains));
171 EXPECT_FALSE(ParseHSTSHeader(" includeSubDomains; ",
172 &max_age, &include_subdomains));
173 EXPECT_FALSE(ParseHSTSHeader(";",
174 &max_age, &include_subdomains));
175 EXPECT_FALSE(ParseHSTSHeader("max-age; ;",
176 &max_age, &include_subdomains));
178 // Check the out args were not updated by checking the default
179 // values for its predictable fields.
180 EXPECT_EQ(0, max_age.InSeconds());
181 EXPECT_FALSE(include_subdomains);
184 static void TestBogusPinsHeaders(HashValueTag tag) {
185 base::TimeDelta max_age;
186 bool include_subdomains;
187 HashValueVector hashes;
188 HashValueVector chain_hashes;
189 GURL report_uri;
191 // Set some fake "chain" hashes
192 chain_hashes.push_back(GetTestHashValue(1, tag));
193 chain_hashes.push_back(GetTestHashValue(2, tag));
194 chain_hashes.push_back(GetTestHashValue(3, tag));
196 // The good pin must be in the chain, the backup pin must not be
197 std::string good_pin = GetTestPin(2, tag);
198 std::string good_pin_unquoted = GetTestPinUnquoted(2, tag);
199 std::string backup_pin = GetTestPin(4, tag);
201 EXPECT_FALSE(ParseAsHPKPHeader(std::string(), chain_hashes, &max_age,
202 &include_subdomains, &hashes, &report_uri));
203 EXPECT_FALSE(ParseAsHPKPHeader(" ", chain_hashes, &max_age,
204 &include_subdomains, &hashes, &report_uri));
205 EXPECT_FALSE(ParseAsHPKPHeader("abc", chain_hashes, &max_age,
206 &include_subdomains, &hashes, &report_uri));
207 EXPECT_FALSE(ParseAsHPKPHeader(" abc", chain_hashes, &max_age,
208 &include_subdomains, &hashes, &report_uri));
209 EXPECT_FALSE(ParseAsHPKPHeader(" abc ", chain_hashes, &max_age,
210 &include_subdomains, &hashes, &report_uri));
211 EXPECT_FALSE(ParseAsHPKPHeader("max-age", chain_hashes, &max_age,
212 &include_subdomains, &hashes, &report_uri));
213 EXPECT_FALSE(ParseAsHPKPHeader(" max-age", chain_hashes, &max_age,
214 &include_subdomains, &hashes, &report_uri));
215 EXPECT_FALSE(ParseAsHPKPHeader(" max-age ", chain_hashes, &max_age,
216 &include_subdomains, &hashes, &report_uri));
217 EXPECT_FALSE(ParseAsHPKPHeader("max-age=", chain_hashes, &max_age,
218 &include_subdomains, &hashes, &report_uri));
219 EXPECT_FALSE(ParseAsHPKPHeader(" max-age=", chain_hashes, &max_age,
220 &include_subdomains, &hashes, &report_uri));
221 EXPECT_FALSE(ParseAsHPKPHeader(" max-age =", chain_hashes, &max_age,
222 &include_subdomains, &hashes, &report_uri));
223 EXPECT_FALSE(ParseAsHPKPHeader(" max-age= ", chain_hashes, &max_age,
224 &include_subdomains, &hashes, &report_uri));
225 EXPECT_FALSE(ParseAsHPKPHeader(" max-age = ", chain_hashes, &max_age,
226 &include_subdomains, &hashes, &report_uri));
227 EXPECT_FALSE(ParseAsHPKPHeader(" max-age = xy", chain_hashes, &max_age,
228 &include_subdomains, &hashes, &report_uri));
229 EXPECT_FALSE(ParseAsHPKPHeader(" max-age = 3488a923", chain_hashes,
230 &max_age, &include_subdomains, &hashes,
231 &report_uri));
232 EXPECT_FALSE(ParseAsHPKPHeader("max-age=3488a923 ", chain_hashes, &max_age,
233 &include_subdomains, &hashes, &report_uri));
234 EXPECT_FALSE(ParseAsHPKPHeader(
235 "max-ag=3488923pins=" + good_pin + "," + backup_pin, chain_hashes,
236 &max_age, &include_subdomains, &hashes, &report_uri));
237 EXPECT_FALSE(ParseAsHPKPHeader(
238 "max-age=3488923;pins=" + good_pin + "," + backup_pin +
239 "report-uri=\"http://foo.com\"",
240 chain_hashes, &max_age, &include_subdomains, &hashes, &report_uri));
241 EXPECT_FALSE(ParseAsHPKPHeader("max-aged=3488923" + backup_pin, chain_hashes,
242 &max_age, &include_subdomains, &hashes,
243 &report_uri));
244 EXPECT_FALSE(ParseAsHPKPHeader("max-aged=3488923; " + backup_pin,
245 chain_hashes, &max_age, &include_subdomains,
246 &hashes, &report_uri));
247 EXPECT_FALSE(ParseAsHPKPHeader(
248 "max-aged=3488923; " + backup_pin + ";" + backup_pin, chain_hashes,
249 &max_age, &include_subdomains, &hashes, &report_uri));
250 EXPECT_FALSE(ParseAsHPKPHeader(
251 "max-aged=3488923; " + good_pin + ";" + good_pin, chain_hashes, &max_age,
252 &include_subdomains, &hashes, &report_uri));
253 EXPECT_FALSE(ParseAsHPKPHeader("max-aged=3488923; " + good_pin, chain_hashes,
254 &max_age, &include_subdomains, &hashes,
255 &report_uri));
256 EXPECT_FALSE(ParseAsHPKPHeader("max-age==3488923", chain_hashes, &max_age,
257 &include_subdomains, &hashes, &report_uri));
258 EXPECT_FALSE(ParseAsHPKPHeader("amax-age=3488923", chain_hashes, &max_age,
259 &include_subdomains, &hashes, &report_uri));
260 EXPECT_FALSE(ParseAsHPKPHeader("max-age=-3488923", chain_hashes, &max_age,
261 &include_subdomains, &hashes, &report_uri));
262 EXPECT_FALSE(ParseAsHPKPHeader("max-age=3488923;", chain_hashes, &max_age,
263 &include_subdomains, &hashes, &report_uri));
264 EXPECT_FALSE(ParseAsHPKPHeader("max-age=3488923 e", chain_hashes,
265 &max_age, &include_subdomains, &hashes,
266 &report_uri));
267 EXPECT_FALSE(ParseAsHPKPHeader("max-age=3488923 includesubdomain",
268 chain_hashes, &max_age, &include_subdomains,
269 &hashes, &report_uri));
270 EXPECT_FALSE(ParseAsHPKPHeader(
271 "max-age=3488923 report-uri=\"http://foo.com\"", chain_hashes,
272 &max_age, &include_subdomains, &hashes, &report_uri));
273 EXPECT_FALSE(ParseAsHPKPHeader("max-age=34889.23", chain_hashes, &max_age,
274 &include_subdomains, &hashes, &report_uri));
275 EXPECT_FALSE(ParseAsHPKPHeader(
276 "max-age=243; " + good_pin_unquoted + ";" + backup_pin, chain_hashes,
277 &max_age, &include_subdomains, &hashes, &report_uri));
278 EXPECT_FALSE(ParseAsHPKPHeader(
279 "max-age=243; " + good_pin + ";" + backup_pin + ";report-uri=;",
280 chain_hashes, &max_age, &include_subdomains, &hashes, &report_uri));
281 EXPECT_FALSE(ParseAsHPKPHeader("max-age=243; " + good_pin + ";" + backup_pin +
282 ";report-uri=http://foo.com;",
283 chain_hashes, &max_age, &include_subdomains,
284 &hashes, &report_uri));
285 EXPECT_FALSE(ParseAsHPKPHeader(
286 "max-age=243; " + good_pin + ";" + backup_pin + ";report-uri=''",
287 chain_hashes, &max_age, &include_subdomains, &hashes, &report_uri));
289 // Test that the parser rejects misquoted strings.
290 EXPECT_FALSE(ParseAsHPKPHeader(
291 "max-age=999; " + backup_pin + "; " + good_pin +
292 "; report-uri=\"http://foo;bar\'",
293 chain_hashes, &max_age, &include_subdomains, &hashes, &report_uri));
295 // Test that the parser rejects invalid report-uris.
296 EXPECT_FALSE(ParseAsHPKPHeader("max-age=999; " + backup_pin + "; " +
297 good_pin + "; report-uri=\"foo;bar\'",
298 chain_hashes, &max_age, &include_subdomains,
299 &hashes, &report_uri));
301 // Check the out args were not updated by checking the default
302 // values for its predictable fields.
303 EXPECT_EQ(0, max_age.InSeconds());
304 EXPECT_EQ(hashes.size(), (size_t)0);
307 TEST_F(HttpSecurityHeadersTest, ValidSTSHeaders) {
308 base::TimeDelta max_age;
309 base::TimeDelta expect_max_age;
310 bool include_subdomains = false;
312 EXPECT_TRUE(ParseHSTSHeader("max-age=243", &max_age,
313 &include_subdomains));
314 expect_max_age = base::TimeDelta::FromSeconds(243);
315 EXPECT_EQ(expect_max_age, max_age);
316 EXPECT_FALSE(include_subdomains);
318 EXPECT_TRUE(ParseHSTSHeader("max-age=3488923;", &max_age,
319 &include_subdomains));
321 EXPECT_TRUE(ParseHSTSHeader(" Max-agE = 567", &max_age,
322 &include_subdomains));
323 expect_max_age = base::TimeDelta::FromSeconds(567);
324 EXPECT_EQ(expect_max_age, max_age);
325 EXPECT_FALSE(include_subdomains);
327 EXPECT_TRUE(ParseHSTSHeader(" mAx-aGe = 890 ", &max_age,
328 &include_subdomains));
329 expect_max_age = base::TimeDelta::FromSeconds(890);
330 EXPECT_EQ(expect_max_age, max_age);
331 EXPECT_FALSE(include_subdomains);
333 EXPECT_TRUE(ParseHSTSHeader("max-age=123;incLudesUbdOmains", &max_age,
334 &include_subdomains));
335 expect_max_age = base::TimeDelta::FromSeconds(123);
336 EXPECT_EQ(expect_max_age, max_age);
337 EXPECT_TRUE(include_subdomains);
339 EXPECT_TRUE(ParseHSTSHeader("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(" 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(
352 " incLudesUbdOmains; max-age=123; pumpkin=kitten", &max_age,
353 &include_subdomains));
354 expect_max_age = base::TimeDelta::FromSeconds(123);
355 EXPECT_EQ(expect_max_age, max_age);
356 EXPECT_TRUE(include_subdomains);
358 EXPECT_TRUE(ParseHSTSHeader(
359 " pumpkin=894; incLudesUbdOmains; max-age=123 ", &max_age,
360 &include_subdomains));
361 expect_max_age = base::TimeDelta::FromSeconds(123);
362 EXPECT_EQ(expect_max_age, max_age);
363 EXPECT_TRUE(include_subdomains);
365 EXPECT_TRUE(ParseHSTSHeader(
366 " pumpkin; incLudesUbdOmains; max-age=123 ", &max_age,
367 &include_subdomains));
368 expect_max_age = base::TimeDelta::FromSeconds(123);
369 EXPECT_EQ(expect_max_age, max_age);
370 EXPECT_TRUE(include_subdomains);
372 EXPECT_TRUE(ParseHSTSHeader(
373 " pumpkin; incLudesUbdOmains; max-age=\"123\" ", &max_age,
374 &include_subdomains));
375 expect_max_age = base::TimeDelta::FromSeconds(123);
376 EXPECT_EQ(expect_max_age, max_age);
377 EXPECT_TRUE(include_subdomains);
379 EXPECT_TRUE(ParseHSTSHeader(
380 "animal=\"squirrel; distinguished\"; incLudesUbdOmains; max-age=123",
381 &max_age, &include_subdomains));
382 expect_max_age = base::TimeDelta::FromSeconds(123);
383 EXPECT_EQ(expect_max_age, max_age);
384 EXPECT_TRUE(include_subdomains);
386 EXPECT_TRUE(ParseHSTSHeader("max-age=394082; incLudesUbdOmains",
387 &max_age, &include_subdomains));
388 expect_max_age = base::TimeDelta::FromSeconds(394082);
389 EXPECT_EQ(expect_max_age, max_age);
390 EXPECT_TRUE(include_subdomains);
392 EXPECT_TRUE(ParseHSTSHeader(
393 "max-age=39408299 ;incLudesUbdOmains", &max_age,
394 &include_subdomains));
395 expect_max_age = base::TimeDelta::FromSeconds(
396 std::min(kMaxHSTSAgeSecs, static_cast<int64>(INT64_C(39408299))));
397 EXPECT_EQ(expect_max_age, max_age);
398 EXPECT_TRUE(include_subdomains);
400 EXPECT_TRUE(ParseHSTSHeader(
401 "max-age=394082038 ; incLudesUbdOmains", &max_age,
402 &include_subdomains));
403 expect_max_age = base::TimeDelta::FromSeconds(
404 std::min(kMaxHSTSAgeSecs, static_cast<int64>(INT64_C(394082038))));
405 EXPECT_EQ(expect_max_age, max_age);
406 EXPECT_TRUE(include_subdomains);
408 EXPECT_TRUE(ParseHSTSHeader(
409 "max-age=394082038 ; incLudesUbdOmains;", &max_age,
410 &include_subdomains));
411 expect_max_age = base::TimeDelta::FromSeconds(
412 std::min(kMaxHSTSAgeSecs, static_cast<int64>(INT64_C(394082038))));
413 EXPECT_EQ(expect_max_age, max_age);
414 EXPECT_TRUE(include_subdomains);
416 EXPECT_TRUE(ParseHSTSHeader(
417 ";; max-age=394082038 ; incLudesUbdOmains; ;", &max_age,
418 &include_subdomains));
419 expect_max_age = base::TimeDelta::FromSeconds(
420 std::min(kMaxHSTSAgeSecs, static_cast<int64>(INT64_C(394082038))));
421 EXPECT_EQ(expect_max_age, max_age);
422 EXPECT_TRUE(include_subdomains);
424 EXPECT_TRUE(ParseHSTSHeader(
425 ";; max-age=394082038 ;", &max_age,
426 &include_subdomains));
427 expect_max_age = base::TimeDelta::FromSeconds(
428 std::min(kMaxHSTSAgeSecs, static_cast<int64>(INT64_C(394082038))));
429 EXPECT_EQ(expect_max_age, max_age);
430 EXPECT_FALSE(include_subdomains);
432 EXPECT_TRUE(ParseHSTSHeader(
433 ";; ; ; max-age=394082038;;; includeSubdomains ;; ;", &max_age,
434 &include_subdomains));
435 expect_max_age = base::TimeDelta::FromSeconds(
436 std::min(kMaxHSTSAgeSecs, static_cast<int64>(INT64_C(394082038))));
437 EXPECT_EQ(expect_max_age, max_age);
438 EXPECT_TRUE(include_subdomains);
440 EXPECT_TRUE(ParseHSTSHeader(
441 "incLudesUbdOmains ; max-age=394082038 ;;", &max_age,
442 &include_subdomains));
443 expect_max_age = base::TimeDelta::FromSeconds(
444 std::min(kMaxHSTSAgeSecs, static_cast<int64>(INT64_C(394082038))));
445 EXPECT_EQ(expect_max_age, max_age);
446 EXPECT_TRUE(include_subdomains);
448 EXPECT_TRUE(ParseHSTSHeader(
449 " max-age=0 ; incLudesUbdOmains ", &max_age,
450 &include_subdomains));
451 expect_max_age = base::TimeDelta::FromSeconds(0);
452 EXPECT_EQ(expect_max_age, max_age);
453 EXPECT_TRUE(include_subdomains);
455 EXPECT_TRUE(ParseHSTSHeader(
456 " max-age=999999999999999999999999999999999999999999999 ;"
457 " incLudesUbdOmains ", &max_age, &include_subdomains));
458 expect_max_age = base::TimeDelta::FromSeconds(
459 kMaxHSTSAgeSecs);
460 EXPECT_EQ(expect_max_age, max_age);
461 EXPECT_TRUE(include_subdomains);
464 static void TestValidPKPHeaders(HashValueTag tag) {
465 base::TimeDelta max_age;
466 base::TimeDelta expect_max_age;
467 bool include_subdomains;
468 HashValueVector hashes;
469 HashValueVector chain_hashes;
470 GURL expect_report_uri;
471 GURL report_uri;
473 // Set some fake "chain" hashes into chain_hashes
474 chain_hashes.push_back(GetTestHashValue(1, tag));
475 chain_hashes.push_back(GetTestHashValue(2, tag));
476 chain_hashes.push_back(GetTestHashValue(3, tag));
478 // The good pin must be in the chain, the backup pin must not be
479 std::string good_pin = GetTestPin(2, tag);
480 std::string good_pin2 = GetTestPin(3, tag);
481 std::string backup_pin = GetTestPin(4, tag);
483 EXPECT_TRUE(ParseAsHPKPHeader("max-age=243; " + good_pin + ";" + backup_pin,
484 chain_hashes, &max_age, &include_subdomains,
485 &hashes, &report_uri));
486 expect_max_age = base::TimeDelta::FromSeconds(243);
487 EXPECT_EQ(expect_max_age, max_age);
488 EXPECT_FALSE(include_subdomains);
489 EXPECT_TRUE(report_uri.is_empty());
491 EXPECT_TRUE(ParseAsHPKPHeader("max-age=243; " + good_pin + ";" + backup_pin +
492 "; report-uri= \"http://example.test/foo\"",
493 chain_hashes, &max_age, &include_subdomains,
494 &hashes, &report_uri));
495 expect_max_age = base::TimeDelta::FromSeconds(243);
496 expect_report_uri = GURL("http://example.test/foo");
497 EXPECT_EQ(expect_max_age, max_age);
498 EXPECT_FALSE(include_subdomains);
499 EXPECT_EQ(expect_report_uri, report_uri);
501 EXPECT_TRUE(ParseAsHPKPHeader(
502 " " + good_pin + "; " + backup_pin +
503 " ; Max-agE = 567; repOrT-URi = \"http://example.test/foo\"",
504 chain_hashes, &max_age, &include_subdomains, &hashes, &report_uri));
505 expect_max_age = base::TimeDelta::FromSeconds(567);
506 expect_report_uri = GURL("http://example.test/foo");
507 EXPECT_EQ(expect_max_age, max_age);
508 EXPECT_FALSE(include_subdomains);
509 EXPECT_EQ(expect_report_uri, report_uri);
511 EXPECT_TRUE(ParseAsHPKPHeader("includeSubDOMAINS;" + good_pin + ";" +
512 backup_pin + " ; mAx-aGe = 890 ",
513 chain_hashes, &max_age, &include_subdomains,
514 &hashes, &report_uri));
515 expect_max_age = base::TimeDelta::FromSeconds(890);
516 EXPECT_EQ(expect_max_age, max_age);
517 EXPECT_TRUE(include_subdomains);
519 EXPECT_TRUE(ParseAsHPKPHeader(
520 good_pin + ";" + backup_pin + "; max-age=123;IGNORED;", chain_hashes,
521 &max_age, &include_subdomains, &hashes, &report_uri));
522 expect_max_age = base::TimeDelta::FromSeconds(123);
523 EXPECT_EQ(expect_max_age, max_age);
524 EXPECT_FALSE(include_subdomains);
526 EXPECT_TRUE(ParseAsHPKPHeader(
527 "max-age=394082;" + backup_pin + ";" + good_pin + "; ", chain_hashes,
528 &max_age, &include_subdomains, &hashes, &report_uri));
529 expect_max_age = base::TimeDelta::FromSeconds(394082);
530 EXPECT_EQ(expect_max_age, max_age);
531 EXPECT_FALSE(include_subdomains);
533 EXPECT_TRUE(ParseAsHPKPHeader(
534 "max-age=39408299 ;" + backup_pin + ";" + good_pin + "; ", chain_hashes,
535 &max_age, &include_subdomains, &hashes, &report_uri));
536 expect_max_age = base::TimeDelta::FromSeconds(
537 std::min(kMaxHSTSAgeSecs, static_cast<int64>(INT64_C(39408299))));
538 EXPECT_EQ(expect_max_age, max_age);
539 EXPECT_FALSE(include_subdomains);
541 EXPECT_TRUE(ParseAsHPKPHeader(
542 "max-age=39408038 ; cybers=39408038 ; includeSubdomains; " +
543 good_pin + ";" + backup_pin + "; ",
544 chain_hashes, &max_age, &include_subdomains, &hashes, &report_uri));
545 expect_max_age = base::TimeDelta::FromSeconds(
546 std::min(kMaxHSTSAgeSecs, static_cast<int64>(INT64_C(394082038))));
547 EXPECT_EQ(expect_max_age, max_age);
548 EXPECT_TRUE(include_subdomains);
550 EXPECT_TRUE(ParseAsHPKPHeader(
551 " max-age=0 ; " + good_pin + ";" + backup_pin, chain_hashes, &max_age,
552 &include_subdomains, &hashes, &report_uri));
553 expect_max_age = base::TimeDelta::FromSeconds(0);
554 EXPECT_EQ(expect_max_age, max_age);
555 EXPECT_FALSE(include_subdomains);
557 EXPECT_TRUE(ParseAsHPKPHeader(
558 " max-age=0 ; includeSubdomains; " + good_pin + ";" + backup_pin,
559 chain_hashes, &max_age, &include_subdomains, &hashes, &report_uri));
560 expect_max_age = base::TimeDelta::FromSeconds(0);
561 EXPECT_EQ(expect_max_age, max_age);
562 EXPECT_TRUE(include_subdomains);
564 EXPECT_TRUE(ParseAsHPKPHeader(
565 " max-age=999999999999999999999999999999999999999999999 ; " +
566 backup_pin + ";" + good_pin + "; ",
567 chain_hashes, &max_age, &include_subdomains, &hashes, &report_uri));
568 expect_max_age = base::TimeDelta::FromSeconds(kMaxHSTSAgeSecs);
569 EXPECT_EQ(expect_max_age, max_age);
570 EXPECT_FALSE(include_subdomains);
572 EXPECT_TRUE(ParseAsHPKPHeader(
573 " max-age=999999999999999999999999999999999999999999999 ; " +
574 backup_pin + ";" + good_pin +
575 "; report-uri=\"http://example.test/foo\"",
576 chain_hashes, &max_age, &include_subdomains, &hashes, &report_uri));
577 expect_max_age = base::TimeDelta::FromSeconds(kMaxHSTSAgeSecs);
578 expect_report_uri = GURL("http://example.test/foo");
579 EXPECT_EQ(expect_max_age, max_age);
580 EXPECT_FALSE(include_subdomains);
581 EXPECT_EQ(expect_report_uri, report_uri);
583 // Test that parsing a different header resets the hashes.
584 hashes.clear();
585 EXPECT_TRUE(ParseAsHPKPHeader(
586 " max-age=999; " + backup_pin + ";" + good_pin + "; ", chain_hashes,
587 &max_age, &include_subdomains, &hashes, &report_uri));
588 EXPECT_EQ(2u, hashes.size());
589 EXPECT_TRUE(ParseAsHPKPHeader(
590 " max-age=999; " + backup_pin + ";" + good_pin2 + "; ", chain_hashes,
591 &max_age, &include_subdomains, &hashes, &report_uri));
592 EXPECT_EQ(2u, hashes.size());
594 // Test that the parser correctly parses an unencoded ';' inside a
595 // quoted report-uri.
596 EXPECT_TRUE(ParseAsHPKPHeader("max-age=999; " + backup_pin + "; " + good_pin +
597 "; report-uri=\"http://foo.com/?;bar\"",
598 chain_hashes, &max_age, &include_subdomains,
599 &hashes, &report_uri));
600 expect_max_age = base::TimeDelta::FromSeconds(999);
601 expect_report_uri = GURL("http://foo.com/?;bar");
602 EXPECT_EQ(expect_max_age, max_age);
603 EXPECT_FALSE(include_subdomains);
604 EXPECT_EQ(expect_report_uri, report_uri);
606 // Test that the parser correctly parses a report-uri with a >0x7f
607 // character.
608 std::string uri = "http://foo.com/";
609 uri += char(0x7f);
610 expect_report_uri = GURL(uri);
611 EXPECT_TRUE(ParseAsHPKPHeader("max-age=999; " + backup_pin + "; " + good_pin +
612 "; report-uri=\"" + uri + "\"",
613 chain_hashes, &max_age, &include_subdomains,
614 &hashes, &report_uri));
615 expect_max_age = base::TimeDelta::FromSeconds(999);
616 EXPECT_EQ(expect_max_age, max_age);
617 EXPECT_FALSE(include_subdomains);
618 EXPECT_EQ(expect_report_uri, report_uri);
620 // Test that the parser allows quoted max-age values.
621 EXPECT_TRUE(ParseAsHPKPHeader(
622 "max-age='999'; " + backup_pin + "; " + good_pin, chain_hashes, &max_age,
623 &include_subdomains, &hashes, &report_uri));
624 expect_max_age = base::TimeDelta::FromSeconds(999);
625 EXPECT_EQ(expect_max_age, max_age);
626 EXPECT_FALSE(include_subdomains);
628 // Test that the parser handles escaped values.
629 expect_report_uri = GURL("http://foo.com'a");
630 EXPECT_TRUE(ParseAsHPKPHeader("max-age=999; " + backup_pin + "; " + good_pin +
631 "; report-uri='http://foo.com\\'\\a'",
632 chain_hashes, &max_age, &include_subdomains,
633 &hashes, &report_uri));
634 expect_max_age = base::TimeDelta::FromSeconds(999);
635 EXPECT_EQ(expect_max_age, max_age);
636 EXPECT_FALSE(include_subdomains);
637 EXPECT_EQ(expect_report_uri, report_uri);
639 // Test that the parser does not require max-age for Report-Only
640 // headers.
641 expect_report_uri = GURL("http://foo.com");
642 EXPECT_TRUE(ParseHPKPReportOnlyHeader(
643 backup_pin + "; " + good_pin + "; report-uri='http://foo.com'",
644 &include_subdomains, &hashes, &report_uri));
645 EXPECT_EQ(expect_report_uri, report_uri);
648 TEST_F(HttpSecurityHeadersTest, BogusPinsHeadersSHA1) {
649 TestBogusPinsHeaders(HASH_VALUE_SHA1);
652 TEST_F(HttpSecurityHeadersTest, BogusPinsHeadersSHA256) {
653 TestBogusPinsHeaders(HASH_VALUE_SHA256);
656 TEST_F(HttpSecurityHeadersTest, ValidPKPHeadersSHA1) {
657 TestValidPKPHeaders(HASH_VALUE_SHA1);
660 TEST_F(HttpSecurityHeadersTest, ValidPKPHeadersSHA256) {
661 TestValidPKPHeaders(HASH_VALUE_SHA256);
664 TEST_F(HttpSecurityHeadersTest, UpdateDynamicPKPOnly) {
665 TransportSecurityState state;
666 TransportSecurityState::STSState static_sts_state;
667 TransportSecurityState::PKPState static_pkp_state;
669 // docs.google.com has preloaded pins.
670 std::string domain = "docs.google.com";
671 state.enable_static_pins_ = true;
672 EXPECT_TRUE(
673 state.GetStaticDomainState(domain, &static_sts_state, &static_pkp_state));
674 EXPECT_GT(static_pkp_state.spki_hashes.size(), 1UL);
675 HashValueVector saved_hashes = static_pkp_state.spki_hashes;
677 // Add a header, which should only update the dynamic state.
678 HashValue good_hash = GetTestHashValue(1, HASH_VALUE_SHA1);
679 HashValue backup_hash = GetTestHashValue(2, HASH_VALUE_SHA1);
680 std::string good_pin = GetTestPin(1, HASH_VALUE_SHA1);
681 std::string backup_pin = GetTestPin(2, HASH_VALUE_SHA1);
682 GURL report_uri("http://google.com");
683 std::string header = "max-age = 10000; " + good_pin + "; " + backup_pin +
684 ";report-uri=\"" + report_uri.spec() + "\"";
686 // Construct a fake SSLInfo that will pass AddHPKPHeader's checks.
687 SSLInfo ssl_info;
688 ssl_info.public_key_hashes.push_back(good_hash);
689 ssl_info.public_key_hashes.push_back(saved_hashes[0]);
690 EXPECT_TRUE(state.AddHPKPHeader(domain, header, ssl_info));
692 // Expect the static state to remain unchanged.
693 TransportSecurityState::STSState new_static_sts_state;
694 TransportSecurityState::PKPState new_static_pkp_state;
695 EXPECT_TRUE(state.GetStaticDomainState(domain, &new_static_sts_state,
696 &new_static_pkp_state));
697 for (size_t i = 0; i < saved_hashes.size(); ++i) {
698 EXPECT_TRUE(
699 HashValuesEqual(saved_hashes[i])(new_static_pkp_state.spki_hashes[i]));
702 // Expect the dynamic state to reflect the header.
703 TransportSecurityState::PKPState dynamic_pkp_state;
704 EXPECT_TRUE(state.GetDynamicPKPState(domain, &dynamic_pkp_state));
705 EXPECT_EQ(2UL, dynamic_pkp_state.spki_hashes.size());
706 EXPECT_EQ(report_uri, dynamic_pkp_state.report_uri);
708 HashValueVector::const_iterator hash = std::find_if(
709 dynamic_pkp_state.spki_hashes.begin(),
710 dynamic_pkp_state.spki_hashes.end(), HashValuesEqual(good_hash));
711 EXPECT_NE(dynamic_pkp_state.spki_hashes.end(), hash);
713 hash = std::find_if(dynamic_pkp_state.spki_hashes.begin(),
714 dynamic_pkp_state.spki_hashes.end(),
715 HashValuesEqual(backup_hash));
716 EXPECT_NE(dynamic_pkp_state.spki_hashes.end(), hash);
718 // Expect the overall state to reflect the header, too.
719 EXPECT_TRUE(state.HasPublicKeyPins(domain));
720 HashValueVector hashes;
721 hashes.push_back(good_hash);
722 std::string failure_log;
723 const bool is_issued_by_known_root = true;
724 HostPortPair domain_port(domain, 443);
725 EXPECT_TRUE(state.CheckPublicKeyPins(
726 domain_port, is_issued_by_known_root, hashes, nullptr, nullptr,
727 TransportSecurityState::DISABLE_PIN_REPORTS, &failure_log));
729 TransportSecurityState::PKPState new_dynamic_pkp_state;
730 EXPECT_TRUE(state.GetDynamicPKPState(domain, &new_dynamic_pkp_state));
731 EXPECT_EQ(2UL, new_dynamic_pkp_state.spki_hashes.size());
732 EXPECT_EQ(report_uri, new_dynamic_pkp_state.report_uri);
734 hash = std::find_if(new_dynamic_pkp_state.spki_hashes.begin(),
735 new_dynamic_pkp_state.spki_hashes.end(),
736 HashValuesEqual(good_hash));
737 EXPECT_NE(new_dynamic_pkp_state.spki_hashes.end(), hash);
739 hash = std::find_if(new_dynamic_pkp_state.spki_hashes.begin(),
740 new_dynamic_pkp_state.spki_hashes.end(),
741 HashValuesEqual(backup_hash));
742 EXPECT_NE(new_dynamic_pkp_state.spki_hashes.end(), hash);
745 TEST_F(HttpSecurityHeadersTest, UpdateDynamicPKPMaxAge0) {
746 TransportSecurityState state;
747 TransportSecurityState::STSState static_sts_state;
748 TransportSecurityState::PKPState static_pkp_state;
750 // docs.google.com has preloaded pins.
751 std::string domain = "docs.google.com";
752 state.enable_static_pins_ = true;
753 ASSERT_TRUE(
754 state.GetStaticDomainState(domain, &static_sts_state, &static_pkp_state));
755 EXPECT_GT(static_pkp_state.spki_hashes.size(), 1UL);
756 HashValueVector saved_hashes = static_pkp_state.spki_hashes;
758 // Add a header, which should only update the dynamic state.
759 HashValue good_hash = GetTestHashValue(1, HASH_VALUE_SHA1);
760 std::string good_pin = GetTestPin(1, HASH_VALUE_SHA1);
761 std::string backup_pin = GetTestPin(2, HASH_VALUE_SHA1);
762 std::string header = "max-age = 10000; " + good_pin + "; " + backup_pin;
764 // Construct a fake SSLInfo that will pass AddHPKPHeader's checks.
765 SSLInfo ssl_info;
766 ssl_info.public_key_hashes.push_back(good_hash);
767 ssl_info.public_key_hashes.push_back(saved_hashes[0]);
768 EXPECT_TRUE(state.AddHPKPHeader(domain, header, ssl_info));
770 // Expect the static state to remain unchanged.
771 TransportSecurityState::STSState new_static_sts_state;
772 TransportSecurityState::PKPState new_static_pkp_state;
773 EXPECT_TRUE(state.GetStaticDomainState(domain, &new_static_sts_state,
774 &new_static_pkp_state));
775 EXPECT_EQ(saved_hashes.size(), new_static_pkp_state.spki_hashes.size());
776 for (size_t i = 0; i < saved_hashes.size(); ++i) {
777 EXPECT_TRUE(
778 HashValuesEqual(saved_hashes[i])(new_static_pkp_state.spki_hashes[i]));
781 // Expect the dynamic state to have pins.
782 TransportSecurityState::PKPState new_dynamic_pkp_state;
783 EXPECT_TRUE(state.GetDynamicPKPState(domain, &new_dynamic_pkp_state));
784 EXPECT_EQ(2UL, new_dynamic_pkp_state.spki_hashes.size());
785 EXPECT_TRUE(new_dynamic_pkp_state.HasPublicKeyPins());
787 // Now set another header with max-age=0, and check that the pins are
788 // cleared in the dynamic state only.
789 header = "max-age = 0; " + good_pin + "; " + backup_pin;
790 EXPECT_TRUE(state.AddHPKPHeader(domain, header, ssl_info));
792 // Expect the static state to remain unchanged.
793 TransportSecurityState::PKPState new_static_pkp_state2;
794 EXPECT_TRUE(state.GetStaticDomainState(domain, &static_sts_state,
795 &new_static_pkp_state2));
796 EXPECT_EQ(saved_hashes.size(), new_static_pkp_state2.spki_hashes.size());
797 for (size_t i = 0; i < saved_hashes.size(); ++i) {
798 EXPECT_TRUE(
799 HashValuesEqual(saved_hashes[i])(new_static_pkp_state2.spki_hashes[i]));
802 // Expect the dynamic pins to be gone.
803 TransportSecurityState::PKPState new_dynamic_pkp_state2;
804 EXPECT_FALSE(state.GetDynamicPKPState(domain, &new_dynamic_pkp_state2));
806 // Expect the exact-matching static policy to continue to apply, even
807 // though dynamic policy has been removed. (This policy may change in the
808 // future, in which case this test must be updated.)
809 EXPECT_TRUE(state.HasPublicKeyPins(domain));
810 EXPECT_TRUE(state.ShouldSSLErrorsBeFatal(domain));
811 std::string failure_log;
813 // Damage the hashes to cause a pin validation failure.
814 new_static_pkp_state2.spki_hashes[0].data()[0] ^= 0x80;
815 new_static_pkp_state2.spki_hashes[1].data()[0] ^= 0x80;
816 new_static_pkp_state2.spki_hashes[2].data()[0] ^= 0x80;
818 const bool is_issued_by_known_root = true;
819 HostPortPair domain_port(domain, 443);
820 EXPECT_FALSE(state.CheckPublicKeyPins(
821 domain_port, is_issued_by_known_root, new_static_pkp_state2.spki_hashes,
822 nullptr, nullptr, TransportSecurityState::DISABLE_PIN_REPORTS,
823 &failure_log));
824 EXPECT_NE(0UL, failure_log.length());
827 // Tests that when a static HSTS and a static HPKP entry are present, adding a
828 // dynamic HSTS header does not clobber the static HPKP entry. Further, adding a
829 // dynamic HPKP entry could not affect the HSTS entry for the site.
830 TEST_F(HttpSecurityHeadersTest, NoClobberPins) {
831 TransportSecurityState state;
832 TransportSecurityState::STSState sts_state;
833 TransportSecurityState::PKPState pkp_state;
835 // accounts.google.com has preloaded pins.
836 std::string domain = "accounts.google.com";
837 state.enable_static_pins_ = true;
839 // Retrieve the static STS and PKP states as it is by default, including its
840 // known good pins.
841 EXPECT_TRUE(state.GetStaticDomainState(domain, &sts_state, &pkp_state));
842 HashValueVector saved_hashes = pkp_state.spki_hashes;
843 EXPECT_TRUE(sts_state.ShouldUpgradeToSSL());
844 EXPECT_TRUE(pkp_state.HasPublicKeyPins());
845 EXPECT_TRUE(state.ShouldUpgradeToSSL(domain));
846 EXPECT_TRUE(state.HasPublicKeyPins(domain));
848 // Add a dynamic HSTS header. CheckPublicKeyPins should still pass when given
849 // the original |saved_hashes|, indicating that the static PKP data is still
850 // configured for the domain.
851 EXPECT_TRUE(state.AddHSTSHeader(domain, "includesubdomains; max-age=10000"));
852 EXPECT_TRUE(state.ShouldUpgradeToSSL(domain));
853 std::string failure_log;
854 const bool is_issued_by_known_root = true;
855 HostPortPair domain_port(domain, 443);
856 EXPECT_TRUE(state.CheckPublicKeyPins(
857 domain_port, is_issued_by_known_root, saved_hashes, nullptr, nullptr,
858 TransportSecurityState::DISABLE_PIN_REPORTS, &failure_log));
860 // Add an HPKP header, which should only update the dynamic state.
861 HashValue good_hash = GetTestHashValue(1, HASH_VALUE_SHA1);
862 std::string good_pin = GetTestPin(1, HASH_VALUE_SHA1);
863 std::string backup_pin = GetTestPin(2, HASH_VALUE_SHA1);
864 std::string header = "max-age = 10000; " + good_pin + "; " + backup_pin;
866 // Construct a fake SSLInfo that will pass AddHPKPHeader's checks.
867 SSLInfo ssl_info;
868 ssl_info.public_key_hashes.push_back(good_hash);
869 ssl_info.public_key_hashes.push_back(saved_hashes[0]);
870 EXPECT_TRUE(state.AddHPKPHeader(domain, header, ssl_info));
872 EXPECT_TRUE(state.AddHPKPHeader(domain, header, ssl_info));
873 // HSTS should still be configured for this domain.
874 EXPECT_TRUE(sts_state.ShouldUpgradeToSSL());
875 EXPECT_TRUE(state.ShouldUpgradeToSSL(domain));
876 // The dynamic pins, which do not match |saved_hashes|, should take
877 // precedence over the static pins and cause the check to fail.
878 EXPECT_FALSE(state.CheckPublicKeyPins(
879 domain_port, is_issued_by_known_root, saved_hashes, nullptr, nullptr,
880 TransportSecurityState::DISABLE_PIN_REPORTS, &failure_log));
883 // Tests that seeing an invalid HPKP header leaves the existing one alone.
884 TEST_F(HttpSecurityHeadersTest, IgnoreInvalidHeaders) {
885 TransportSecurityState state;
887 HashValue good_hash = GetTestHashValue(1, HASH_VALUE_SHA256);
888 std::string good_pin = GetTestPin(1, HASH_VALUE_SHA256);
889 std::string bad_pin = GetTestPin(2, HASH_VALUE_SHA256);
890 std::string backup_pin = GetTestPin(3, HASH_VALUE_SHA256);
892 SSLInfo ssl_info;
893 ssl_info.public_key_hashes.push_back(good_hash);
895 // Add a valid HPKP header.
896 EXPECT_TRUE(state.AddHPKPHeader(
897 "example.com", "max-age = 10000; " + good_pin + "; " + backup_pin,
898 ssl_info));
900 // Check the insertion was valid.
901 EXPECT_TRUE(state.HasPublicKeyPins("example.com"));
902 std::string failure_log;
903 bool is_issued_by_known_root = true;
904 HostPortPair domain_port("example.com", 443);
905 EXPECT_TRUE(state.CheckPublicKeyPins(
906 domain_port, is_issued_by_known_root, ssl_info.public_key_hashes, nullptr,
907 nullptr, TransportSecurityState::DISABLE_PIN_REPORTS, &failure_log));
909 // Now assert an invalid one. This should fail.
910 EXPECT_FALSE(state.AddHPKPHeader(
911 "example.com", "max-age = 10000; " + bad_pin + "; " + backup_pin,
912 ssl_info));
914 // The old pins must still exist.
915 EXPECT_TRUE(state.HasPublicKeyPins("example.com"));
916 EXPECT_TRUE(state.CheckPublicKeyPins(
917 domain_port, is_issued_by_known_root, ssl_info.public_key_hashes, nullptr,
918 nullptr, TransportSecurityState::DISABLE_PIN_REPORTS, &failure_log));
921 }; // namespace net