Revert "Fix broken channel icon in chrome://help on CrOS" and try again
[chromium-blink-merge.git] / net / http / http_security_headers_unittest.cc
blob4a510f2f11d7f86073ec8cc43a5630a8fc4cf3c5
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/strings/string_piece.h"
10 #include "crypto/sha2.h"
11 #include "net/base/host_port_pair.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"
20 namespace net {
22 namespace {
24 HashValue GetTestHashValue(uint8 label, HashValueTag tag) {
25 HashValue hash_value(tag);
26 memset(hash_value.data(), label, hash_value.size());
27 return hash_value;
30 std::string GetTestPinImpl(uint8 label, HashValueTag tag, bool quoted) {
31 HashValue hash_value = GetTestHashValue(label, tag);
32 std::string base64;
33 base::Base64Encode(base::StringPiece(
34 reinterpret_cast<char*>(hash_value.data()), hash_value.size()), &base64);
36 std::string ret;
37 switch (hash_value.tag) {
38 case HASH_VALUE_SHA256:
39 ret = "pin-sha256=";
40 break;
41 default:
42 NOTREACHED() << "Unknown HashValueTag " << hash_value.tag;
43 return std::string("ERROR");
45 if (quoted)
46 ret += '\"';
47 ret += base64;
48 if (quoted)
49 ret += '\"';
50 return ret;
53 std::string GetTestPin(uint8 label, HashValueTag tag) {
54 return GetTestPinImpl(label, tag, true);
57 std::string GetTestPinUnquoted(uint8 label, HashValueTag tag) {
58 return GetTestPinImpl(label, tag, false);
63 // Parses the given header |value| as both a Public-Key-Pins-Report-Only
64 // and Public-Key-Pins header. Returns true if the value parses
65 // successfully for both header types, and if the parsed hashes and
66 // report_uri match for both header types.
67 bool ParseAsHPKPHeader(const std::string& value,
68 const HashValueVector& chain_hashes,
69 base::TimeDelta* max_age,
70 bool* include_subdomains,
71 HashValueVector* hashes,
72 GURL* report_uri) {
73 GURL report_only_uri;
74 bool report_only_include_subdomains;
75 HashValueVector report_only_hashes;
76 if (!ParseHPKPReportOnlyHeader(value, &report_only_include_subdomains,
77 &report_only_hashes, &report_only_uri)) {
78 return false;
81 bool result = ParseHPKPHeader(value, chain_hashes, max_age,
82 include_subdomains, hashes, report_uri);
83 if (!result || report_only_include_subdomains != *include_subdomains ||
84 report_only_uri != *report_uri ||
85 report_only_hashes.size() != hashes->size()) {
86 return false;
89 for (size_t i = 0; i < report_only_hashes.size(); i++) {
90 if (!(*hashes)[i].Equals(report_only_hashes[i]))
91 return false;
94 return true;
97 class HttpSecurityHeadersTest : public testing::Test {
101 TEST_F(HttpSecurityHeadersTest, BogusHeaders) {
102 base::TimeDelta max_age;
103 bool include_subdomains = false;
105 EXPECT_FALSE(
106 ParseHSTSHeader(std::string(), &max_age, &include_subdomains));
107 EXPECT_FALSE(ParseHSTSHeader(" ", &max_age, &include_subdomains));
108 EXPECT_FALSE(ParseHSTSHeader("abc", &max_age, &include_subdomains));
109 EXPECT_FALSE(ParseHSTSHeader(" abc", &max_age, &include_subdomains));
110 EXPECT_FALSE(ParseHSTSHeader(" abc ", &max_age, &include_subdomains));
111 EXPECT_FALSE(ParseHSTSHeader("max-age", &max_age, &include_subdomains));
112 EXPECT_FALSE(ParseHSTSHeader(" max-age", &max_age,
113 &include_subdomains));
114 EXPECT_FALSE(ParseHSTSHeader(" max-age ", &max_age,
115 &include_subdomains));
116 EXPECT_FALSE(ParseHSTSHeader("max-age=", &max_age, &include_subdomains));
117 EXPECT_FALSE(ParseHSTSHeader(" max-age=", &max_age,
118 &include_subdomains));
119 EXPECT_FALSE(ParseHSTSHeader(" max-age =", &max_age,
120 &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 = xy", &max_age,
126 &include_subdomains));
127 EXPECT_FALSE(ParseHSTSHeader(" max-age = 3488a923", &max_age,
128 &include_subdomains));
129 EXPECT_FALSE(ParseHSTSHeader("max-age=3488a923 ", &max_age,
130 &include_subdomains));
131 EXPECT_FALSE(ParseHSTSHeader("max-ag=3488923", &max_age,
132 &include_subdomains));
133 EXPECT_FALSE(ParseHSTSHeader("max-aged=3488923", &max_age,
134 &include_subdomains));
135 EXPECT_FALSE(ParseHSTSHeader("max-age==3488923", &max_age,
136 &include_subdomains));
137 EXPECT_FALSE(ParseHSTSHeader("amax-age=3488923", &max_age,
138 &include_subdomains));
139 EXPECT_FALSE(ParseHSTSHeader("max-age=-3488923", &max_age,
140 &include_subdomains));
141 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923 e", &max_age,
142 &include_subdomains));
143 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923 includesubdomain",
144 &max_age, &include_subdomains));
145 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923includesubdomains",
146 &max_age, &include_subdomains));
147 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923=includesubdomains",
148 &max_age, &include_subdomains));
149 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923 includesubdomainx",
150 &max_age, &include_subdomains));
151 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923 includesubdomain=",
152 &max_age, &include_subdomains));
153 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923 includesubdomain=true",
154 &max_age, &include_subdomains));
155 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923 includesubdomainsx",
156 &max_age, &include_subdomains));
157 EXPECT_FALSE(ParseHSTSHeader("max-age=3488923 includesubdomains x",
158 &max_age, &include_subdomains));
159 EXPECT_FALSE(ParseHSTSHeader("max-age=34889.23 includesubdomains",
160 &max_age, &include_subdomains));
161 EXPECT_FALSE(ParseHSTSHeader("max-age=34889 includesubdomains",
162 &max_age, &include_subdomains));
163 EXPECT_FALSE(ParseHSTSHeader(";;;; ;;;",
164 &max_age, &include_subdomains));
165 EXPECT_FALSE(ParseHSTSHeader(";;;; includeSubDomains;;;",
166 &max_age, &include_subdomains));
167 EXPECT_FALSE(ParseHSTSHeader(" includeSubDomains; ",
168 &max_age, &include_subdomains));
169 EXPECT_FALSE(ParseHSTSHeader(";",
170 &max_age, &include_subdomains));
171 EXPECT_FALSE(ParseHSTSHeader("max-age; ;",
172 &max_age, &include_subdomains));
174 // Check the out args were not updated by checking the default
175 // values for its predictable fields.
176 EXPECT_EQ(0, max_age.InSeconds());
177 EXPECT_FALSE(include_subdomains);
180 static void TestBogusPinsHeaders(HashValueTag tag) {
181 base::TimeDelta max_age;
182 bool include_subdomains;
183 HashValueVector hashes;
184 HashValueVector chain_hashes;
185 GURL report_uri;
187 // Set some fake "chain" hashes
188 chain_hashes.push_back(GetTestHashValue(1, tag));
189 chain_hashes.push_back(GetTestHashValue(2, tag));
190 chain_hashes.push_back(GetTestHashValue(3, tag));
192 // The good pin must be in the chain, the backup pin must not be
193 std::string good_pin = GetTestPin(2, tag);
194 std::string good_pin_unquoted = GetTestPinUnquoted(2, tag);
195 std::string backup_pin = GetTestPin(4, tag);
197 EXPECT_FALSE(ParseAsHPKPHeader(std::string(), chain_hashes, &max_age,
198 &include_subdomains, &hashes, &report_uri));
199 EXPECT_FALSE(ParseAsHPKPHeader(" ", chain_hashes, &max_age,
200 &include_subdomains, &hashes, &report_uri));
201 EXPECT_FALSE(ParseAsHPKPHeader("abc", chain_hashes, &max_age,
202 &include_subdomains, &hashes, &report_uri));
203 EXPECT_FALSE(ParseAsHPKPHeader(" abc", 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("max-age", chain_hashes, &max_age,
208 &include_subdomains, &hashes, &report_uri));
209 EXPECT_FALSE(ParseAsHPKPHeader(" max-age", 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 = xy", chain_hashes, &max_age,
224 &include_subdomains, &hashes, &report_uri));
225 EXPECT_FALSE(ParseAsHPKPHeader(" max-age = 3488a923", chain_hashes,
226 &max_age, &include_subdomains, &hashes,
227 &report_uri));
228 EXPECT_FALSE(ParseAsHPKPHeader("max-age=3488a923 ", chain_hashes, &max_age,
229 &include_subdomains, &hashes, &report_uri));
230 EXPECT_FALSE(ParseAsHPKPHeader(
231 "max-ag=3488923pins=" + good_pin + "," + backup_pin, chain_hashes,
232 &max_age, &include_subdomains, &hashes, &report_uri));
233 EXPECT_FALSE(ParseAsHPKPHeader(
234 "max-age=3488923;pins=" + good_pin + "," + backup_pin +
235 "report-uri=\"http://foo.com\"",
236 chain_hashes, &max_age, &include_subdomains, &hashes, &report_uri));
237 EXPECT_FALSE(ParseAsHPKPHeader("max-aged=3488923" + backup_pin, chain_hashes,
238 &max_age, &include_subdomains, &hashes,
239 &report_uri));
240 EXPECT_FALSE(ParseAsHPKPHeader("max-aged=3488923; " + backup_pin,
241 chain_hashes, &max_age, &include_subdomains,
242 &hashes, &report_uri));
243 EXPECT_FALSE(ParseAsHPKPHeader(
244 "max-aged=3488923; " + backup_pin + ";" + backup_pin, chain_hashes,
245 &max_age, &include_subdomains, &hashes, &report_uri));
246 EXPECT_FALSE(ParseAsHPKPHeader(
247 "max-aged=3488923; " + good_pin + ";" + good_pin, chain_hashes, &max_age,
248 &include_subdomains, &hashes, &report_uri));
249 EXPECT_FALSE(ParseAsHPKPHeader("max-aged=3488923; " + good_pin, chain_hashes,
250 &max_age, &include_subdomains, &hashes,
251 &report_uri));
252 EXPECT_FALSE(ParseAsHPKPHeader("max-age==3488923", chain_hashes, &max_age,
253 &include_subdomains, &hashes, &report_uri));
254 EXPECT_FALSE(ParseAsHPKPHeader("amax-age=3488923", chain_hashes, &max_age,
255 &include_subdomains, &hashes, &report_uri));
256 EXPECT_FALSE(ParseAsHPKPHeader("max-age=-3488923", chain_hashes, &max_age,
257 &include_subdomains, &hashes, &report_uri));
258 EXPECT_FALSE(ParseAsHPKPHeader("max-age=3488923;", chain_hashes, &max_age,
259 &include_subdomains, &hashes, &report_uri));
260 EXPECT_FALSE(ParseAsHPKPHeader("max-age=3488923 e", chain_hashes,
261 &max_age, &include_subdomains, &hashes,
262 &report_uri));
263 EXPECT_FALSE(ParseAsHPKPHeader("max-age=3488923 includesubdomain",
264 chain_hashes, &max_age, &include_subdomains,
265 &hashes, &report_uri));
266 EXPECT_FALSE(ParseAsHPKPHeader(
267 "max-age=3488923 report-uri=\"http://foo.com\"", chain_hashes,
268 &max_age, &include_subdomains, &hashes, &report_uri));
269 EXPECT_FALSE(ParseAsHPKPHeader("max-age=34889.23", chain_hashes, &max_age,
270 &include_subdomains, &hashes, &report_uri));
271 EXPECT_FALSE(ParseAsHPKPHeader(
272 "max-age=243; " + good_pin_unquoted + ";" + backup_pin, chain_hashes,
273 &max_age, &include_subdomains, &hashes, &report_uri));
274 EXPECT_FALSE(ParseAsHPKPHeader(
275 "max-age=243; " + good_pin + ";" + backup_pin + ";report-uri=;",
276 chain_hashes, &max_age, &include_subdomains, &hashes, &report_uri));
277 EXPECT_FALSE(ParseAsHPKPHeader("max-age=243; " + good_pin + ";" + backup_pin +
278 ";report-uri=http://foo.com;",
279 chain_hashes, &max_age, &include_subdomains,
280 &hashes, &report_uri));
281 EXPECT_FALSE(ParseAsHPKPHeader(
282 "max-age=243; " + good_pin + ";" + backup_pin + ";report-uri=''",
283 chain_hashes, &max_age, &include_subdomains, &hashes, &report_uri));
285 // Test that the parser rejects misquoted strings.
286 EXPECT_FALSE(ParseAsHPKPHeader(
287 "max-age=999; " + backup_pin + "; " + good_pin +
288 "; report-uri=\"http://foo;bar\'",
289 chain_hashes, &max_age, &include_subdomains, &hashes, &report_uri));
291 // Test that the parser rejects invalid report-uris.
292 EXPECT_FALSE(ParseAsHPKPHeader("max-age=999; " + backup_pin + "; " +
293 good_pin + "; report-uri=\"foo;bar\'",
294 chain_hashes, &max_age, &include_subdomains,
295 &hashes, &report_uri));
297 // Check the out args were not updated by checking the default
298 // values for its predictable fields.
299 EXPECT_EQ(0, max_age.InSeconds());
300 EXPECT_EQ(hashes.size(), (size_t)0);
303 TEST_F(HttpSecurityHeadersTest, ValidSTSHeaders) {
304 base::TimeDelta max_age;
305 base::TimeDelta expect_max_age;
306 bool include_subdomains = false;
308 EXPECT_TRUE(ParseHSTSHeader("max-age=243", &max_age,
309 &include_subdomains));
310 expect_max_age = base::TimeDelta::FromSeconds(243);
311 EXPECT_EQ(expect_max_age, max_age);
312 EXPECT_FALSE(include_subdomains);
314 EXPECT_TRUE(ParseHSTSHeader("max-age=3488923;", &max_age,
315 &include_subdomains));
317 EXPECT_TRUE(ParseHSTSHeader(" Max-agE = 567", &max_age,
318 &include_subdomains));
319 expect_max_age = base::TimeDelta::FromSeconds(567);
320 EXPECT_EQ(expect_max_age, max_age);
321 EXPECT_FALSE(include_subdomains);
323 EXPECT_TRUE(ParseHSTSHeader(" mAx-aGe = 890 ", &max_age,
324 &include_subdomains));
325 expect_max_age = base::TimeDelta::FromSeconds(890);
326 EXPECT_EQ(expect_max_age, max_age);
327 EXPECT_FALSE(include_subdomains);
329 EXPECT_TRUE(ParseHSTSHeader("max-age=123;incLudesUbdOmains", &max_age,
330 &include_subdomains));
331 expect_max_age = base::TimeDelta::FromSeconds(123);
332 EXPECT_EQ(expect_max_age, max_age);
333 EXPECT_TRUE(include_subdomains);
335 EXPECT_TRUE(ParseHSTSHeader("incLudesUbdOmains; max-age=123", &max_age,
336 &include_subdomains));
337 expect_max_age = base::TimeDelta::FromSeconds(123);
338 EXPECT_EQ(expect_max_age, max_age);
339 EXPECT_TRUE(include_subdomains);
341 EXPECT_TRUE(ParseHSTSHeader(" incLudesUbdOmains; max-age=123",
342 &max_age, &include_subdomains));
343 expect_max_age = base::TimeDelta::FromSeconds(123);
344 EXPECT_EQ(expect_max_age, max_age);
345 EXPECT_TRUE(include_subdomains);
347 EXPECT_TRUE(ParseHSTSHeader(
348 " incLudesUbdOmains; max-age=123; pumpkin=kitten", &max_age,
349 &include_subdomains));
350 expect_max_age = base::TimeDelta::FromSeconds(123);
351 EXPECT_EQ(expect_max_age, max_age);
352 EXPECT_TRUE(include_subdomains);
354 EXPECT_TRUE(ParseHSTSHeader(
355 " pumpkin=894; incLudesUbdOmains; max-age=123 ", &max_age,
356 &include_subdomains));
357 expect_max_age = base::TimeDelta::FromSeconds(123);
358 EXPECT_EQ(expect_max_age, max_age);
359 EXPECT_TRUE(include_subdomains);
361 EXPECT_TRUE(ParseHSTSHeader(
362 " pumpkin; incLudesUbdOmains; max-age=123 ", &max_age,
363 &include_subdomains));
364 expect_max_age = base::TimeDelta::FromSeconds(123);
365 EXPECT_EQ(expect_max_age, max_age);
366 EXPECT_TRUE(include_subdomains);
368 EXPECT_TRUE(ParseHSTSHeader(
369 " pumpkin; incLudesUbdOmains; max-age=\"123\" ", &max_age,
370 &include_subdomains));
371 expect_max_age = base::TimeDelta::FromSeconds(123);
372 EXPECT_EQ(expect_max_age, max_age);
373 EXPECT_TRUE(include_subdomains);
375 EXPECT_TRUE(ParseHSTSHeader(
376 "animal=\"squirrel; distinguished\"; incLudesUbdOmains; max-age=123",
377 &max_age, &include_subdomains));
378 expect_max_age = base::TimeDelta::FromSeconds(123);
379 EXPECT_EQ(expect_max_age, max_age);
380 EXPECT_TRUE(include_subdomains);
382 EXPECT_TRUE(ParseHSTSHeader("max-age=394082; incLudesUbdOmains",
383 &max_age, &include_subdomains));
384 expect_max_age = base::TimeDelta::FromSeconds(394082);
385 EXPECT_EQ(expect_max_age, max_age);
386 EXPECT_TRUE(include_subdomains);
388 EXPECT_TRUE(ParseHSTSHeader(
389 "max-age=39408299 ;incLudesUbdOmains", &max_age,
390 &include_subdomains));
391 expect_max_age = base::TimeDelta::FromSeconds(
392 std::min(kMaxHSTSAgeSecs, static_cast<int64>(INT64_C(39408299))));
393 EXPECT_EQ(expect_max_age, max_age);
394 EXPECT_TRUE(include_subdomains);
396 EXPECT_TRUE(ParseHSTSHeader(
397 "max-age=394082038 ; incLudesUbdOmains", &max_age,
398 &include_subdomains));
399 expect_max_age = base::TimeDelta::FromSeconds(
400 std::min(kMaxHSTSAgeSecs, static_cast<int64>(INT64_C(394082038))));
401 EXPECT_EQ(expect_max_age, max_age);
402 EXPECT_TRUE(include_subdomains);
404 EXPECT_TRUE(ParseHSTSHeader(
405 "max-age=394082038 ; incLudesUbdOmains;", &max_age,
406 &include_subdomains));
407 expect_max_age = base::TimeDelta::FromSeconds(
408 std::min(kMaxHSTSAgeSecs, static_cast<int64>(INT64_C(394082038))));
409 EXPECT_EQ(expect_max_age, max_age);
410 EXPECT_TRUE(include_subdomains);
412 EXPECT_TRUE(ParseHSTSHeader(
413 ";; max-age=394082038 ; incLudesUbdOmains; ;", &max_age,
414 &include_subdomains));
415 expect_max_age = base::TimeDelta::FromSeconds(
416 std::min(kMaxHSTSAgeSecs, static_cast<int64>(INT64_C(394082038))));
417 EXPECT_EQ(expect_max_age, max_age);
418 EXPECT_TRUE(include_subdomains);
420 EXPECT_TRUE(ParseHSTSHeader(
421 ";; max-age=394082038 ;", &max_age,
422 &include_subdomains));
423 expect_max_age = base::TimeDelta::FromSeconds(
424 std::min(kMaxHSTSAgeSecs, static_cast<int64>(INT64_C(394082038))));
425 EXPECT_EQ(expect_max_age, max_age);
426 EXPECT_FALSE(include_subdomains);
428 EXPECT_TRUE(ParseHSTSHeader(
429 ";; ; ; max-age=394082038;;; includeSubdomains ;; ;", &max_age,
430 &include_subdomains));
431 expect_max_age = base::TimeDelta::FromSeconds(
432 std::min(kMaxHSTSAgeSecs, static_cast<int64>(INT64_C(394082038))));
433 EXPECT_EQ(expect_max_age, max_age);
434 EXPECT_TRUE(include_subdomains);
436 EXPECT_TRUE(ParseHSTSHeader(
437 "incLudesUbdOmains ; max-age=394082038 ;;", &max_age,
438 &include_subdomains));
439 expect_max_age = base::TimeDelta::FromSeconds(
440 std::min(kMaxHSTSAgeSecs, static_cast<int64>(INT64_C(394082038))));
441 EXPECT_EQ(expect_max_age, max_age);
442 EXPECT_TRUE(include_subdomains);
444 EXPECT_TRUE(ParseHSTSHeader(
445 " max-age=0 ; incLudesUbdOmains ", &max_age,
446 &include_subdomains));
447 expect_max_age = base::TimeDelta::FromSeconds(0);
448 EXPECT_EQ(expect_max_age, max_age);
449 EXPECT_TRUE(include_subdomains);
451 EXPECT_TRUE(ParseHSTSHeader(
452 " max-age=999999999999999999999999999999999999999999999 ;"
453 " incLudesUbdOmains ", &max_age, &include_subdomains));
454 expect_max_age = base::TimeDelta::FromSeconds(
455 kMaxHSTSAgeSecs);
456 EXPECT_EQ(expect_max_age, max_age);
457 EXPECT_TRUE(include_subdomains);
460 static void TestValidPKPHeaders(HashValueTag tag) {
461 base::TimeDelta max_age;
462 base::TimeDelta expect_max_age;
463 bool include_subdomains;
464 HashValueVector hashes;
465 HashValueVector chain_hashes;
466 GURL expect_report_uri;
467 GURL report_uri;
469 // Set some fake "chain" hashes into chain_hashes
470 chain_hashes.push_back(GetTestHashValue(1, tag));
471 chain_hashes.push_back(GetTestHashValue(2, tag));
472 chain_hashes.push_back(GetTestHashValue(3, tag));
474 // The good pin must be in the chain, the backup pin must not be
475 std::string good_pin = GetTestPin(2, tag);
476 std::string good_pin2 = GetTestPin(3, tag);
477 std::string backup_pin = GetTestPin(4, tag);
479 EXPECT_TRUE(ParseAsHPKPHeader("max-age=243; " + good_pin + ";" + backup_pin,
480 chain_hashes, &max_age, &include_subdomains,
481 &hashes, &report_uri));
482 expect_max_age = base::TimeDelta::FromSeconds(243);
483 EXPECT_EQ(expect_max_age, max_age);
484 EXPECT_FALSE(include_subdomains);
485 EXPECT_TRUE(report_uri.is_empty());
487 EXPECT_TRUE(ParseAsHPKPHeader("max-age=243; " + good_pin + ";" + backup_pin +
488 "; report-uri= \"http://example.test/foo\"",
489 chain_hashes, &max_age, &include_subdomains,
490 &hashes, &report_uri));
491 expect_max_age = base::TimeDelta::FromSeconds(243);
492 expect_report_uri = GURL("http://example.test/foo");
493 EXPECT_EQ(expect_max_age, max_age);
494 EXPECT_FALSE(include_subdomains);
495 EXPECT_EQ(expect_report_uri, report_uri);
497 EXPECT_TRUE(ParseAsHPKPHeader(
498 " " + good_pin + "; " + backup_pin +
499 " ; Max-agE = 567; repOrT-URi = \"http://example.test/foo\"",
500 chain_hashes, &max_age, &include_subdomains, &hashes, &report_uri));
501 expect_max_age = base::TimeDelta::FromSeconds(567);
502 expect_report_uri = GURL("http://example.test/foo");
503 EXPECT_EQ(expect_max_age, max_age);
504 EXPECT_FALSE(include_subdomains);
505 EXPECT_EQ(expect_report_uri, report_uri);
507 EXPECT_TRUE(ParseAsHPKPHeader("includeSubDOMAINS;" + good_pin + ";" +
508 backup_pin + " ; mAx-aGe = 890 ",
509 chain_hashes, &max_age, &include_subdomains,
510 &hashes, &report_uri));
511 expect_max_age = base::TimeDelta::FromSeconds(890);
512 EXPECT_EQ(expect_max_age, max_age);
513 EXPECT_TRUE(include_subdomains);
515 EXPECT_TRUE(ParseAsHPKPHeader(
516 good_pin + ";" + backup_pin + "; max-age=123;IGNORED;", chain_hashes,
517 &max_age, &include_subdomains, &hashes, &report_uri));
518 expect_max_age = base::TimeDelta::FromSeconds(123);
519 EXPECT_EQ(expect_max_age, max_age);
520 EXPECT_FALSE(include_subdomains);
522 EXPECT_TRUE(ParseAsHPKPHeader(
523 "max-age=394082;" + backup_pin + ";" + good_pin + "; ", chain_hashes,
524 &max_age, &include_subdomains, &hashes, &report_uri));
525 expect_max_age = base::TimeDelta::FromSeconds(394082);
526 EXPECT_EQ(expect_max_age, max_age);
527 EXPECT_FALSE(include_subdomains);
529 EXPECT_TRUE(ParseAsHPKPHeader(
530 "max-age=39408299 ;" + backup_pin + ";" + good_pin + "; ", chain_hashes,
531 &max_age, &include_subdomains, &hashes, &report_uri));
532 expect_max_age = base::TimeDelta::FromSeconds(
533 std::min(kMaxHSTSAgeSecs, static_cast<int64>(INT64_C(39408299))));
534 EXPECT_EQ(expect_max_age, max_age);
535 EXPECT_FALSE(include_subdomains);
537 EXPECT_TRUE(ParseAsHPKPHeader(
538 "max-age=39408038 ; cybers=39408038 ; includeSubdomains; " +
539 good_pin + ";" + backup_pin + "; ",
540 chain_hashes, &max_age, &include_subdomains, &hashes, &report_uri));
541 expect_max_age = base::TimeDelta::FromSeconds(
542 std::min(kMaxHSTSAgeSecs, static_cast<int64>(INT64_C(394082038))));
543 EXPECT_EQ(expect_max_age, max_age);
544 EXPECT_TRUE(include_subdomains);
546 EXPECT_TRUE(ParseAsHPKPHeader(
547 " max-age=0 ; " + good_pin + ";" + backup_pin, chain_hashes, &max_age,
548 &include_subdomains, &hashes, &report_uri));
549 expect_max_age = base::TimeDelta::FromSeconds(0);
550 EXPECT_EQ(expect_max_age, max_age);
551 EXPECT_FALSE(include_subdomains);
553 EXPECT_TRUE(ParseAsHPKPHeader(
554 " max-age=0 ; includeSubdomains; " + good_pin + ";" + backup_pin,
555 chain_hashes, &max_age, &include_subdomains, &hashes, &report_uri));
556 expect_max_age = base::TimeDelta::FromSeconds(0);
557 EXPECT_EQ(expect_max_age, max_age);
558 EXPECT_TRUE(include_subdomains);
560 EXPECT_TRUE(ParseAsHPKPHeader(
561 " max-age=999999999999999999999999999999999999999999999 ; " +
562 backup_pin + ";" + good_pin + "; ",
563 chain_hashes, &max_age, &include_subdomains, &hashes, &report_uri));
564 expect_max_age = base::TimeDelta::FromSeconds(kMaxHSTSAgeSecs);
565 EXPECT_EQ(expect_max_age, max_age);
566 EXPECT_FALSE(include_subdomains);
568 EXPECT_TRUE(ParseAsHPKPHeader(
569 " max-age=999999999999999999999999999999999999999999999 ; " +
570 backup_pin + ";" + good_pin +
571 "; report-uri=\"http://example.test/foo\"",
572 chain_hashes, &max_age, &include_subdomains, &hashes, &report_uri));
573 expect_max_age = base::TimeDelta::FromSeconds(kMaxHSTSAgeSecs);
574 expect_report_uri = GURL("http://example.test/foo");
575 EXPECT_EQ(expect_max_age, max_age);
576 EXPECT_FALSE(include_subdomains);
577 EXPECT_EQ(expect_report_uri, report_uri);
579 // Test that parsing a different header resets the hashes.
580 hashes.clear();
581 EXPECT_TRUE(ParseAsHPKPHeader(
582 " max-age=999; " + backup_pin + ";" + good_pin + "; ", chain_hashes,
583 &max_age, &include_subdomains, &hashes, &report_uri));
584 EXPECT_EQ(2u, hashes.size());
585 EXPECT_TRUE(ParseAsHPKPHeader(
586 " max-age=999; " + backup_pin + ";" + good_pin2 + "; ", chain_hashes,
587 &max_age, &include_subdomains, &hashes, &report_uri));
588 EXPECT_EQ(2u, hashes.size());
590 // Test that the parser correctly parses an unencoded ';' inside a
591 // quoted report-uri.
592 EXPECT_TRUE(ParseAsHPKPHeader("max-age=999; " + backup_pin + "; " + good_pin +
593 "; report-uri=\"http://foo.com/?;bar\"",
594 chain_hashes, &max_age, &include_subdomains,
595 &hashes, &report_uri));
596 expect_max_age = base::TimeDelta::FromSeconds(999);
597 expect_report_uri = GURL("http://foo.com/?;bar");
598 EXPECT_EQ(expect_max_age, max_age);
599 EXPECT_FALSE(include_subdomains);
600 EXPECT_EQ(expect_report_uri, report_uri);
602 // Test that the parser correctly parses a report-uri with a >0x7f
603 // character.
604 std::string uri = "http://foo.com/";
605 uri += char(0x7f);
606 expect_report_uri = GURL(uri);
607 EXPECT_TRUE(ParseAsHPKPHeader("max-age=999; " + backup_pin + "; " + good_pin +
608 "; report-uri=\"" + uri + "\"",
609 chain_hashes, &max_age, &include_subdomains,
610 &hashes, &report_uri));
611 expect_max_age = base::TimeDelta::FromSeconds(999);
612 EXPECT_EQ(expect_max_age, max_age);
613 EXPECT_FALSE(include_subdomains);
614 EXPECT_EQ(expect_report_uri, report_uri);
616 // Test that the parser allows quoted max-age values.
617 EXPECT_TRUE(ParseAsHPKPHeader(
618 "max-age='999'; " + backup_pin + "; " + good_pin, chain_hashes, &max_age,
619 &include_subdomains, &hashes, &report_uri));
620 expect_max_age = base::TimeDelta::FromSeconds(999);
621 EXPECT_EQ(expect_max_age, max_age);
622 EXPECT_FALSE(include_subdomains);
624 // Test that the parser handles escaped values.
625 expect_report_uri = GURL("http://foo.com'a");
626 EXPECT_TRUE(ParseAsHPKPHeader("max-age=999; " + backup_pin + "; " + good_pin +
627 "; report-uri='http://foo.com\\'\\a'",
628 chain_hashes, &max_age, &include_subdomains,
629 &hashes, &report_uri));
630 expect_max_age = base::TimeDelta::FromSeconds(999);
631 EXPECT_EQ(expect_max_age, max_age);
632 EXPECT_FALSE(include_subdomains);
633 EXPECT_EQ(expect_report_uri, report_uri);
635 // Test that the parser does not require max-age for Report-Only
636 // headers.
637 expect_report_uri = GURL("http://foo.com");
638 EXPECT_TRUE(ParseHPKPReportOnlyHeader(
639 backup_pin + "; " + good_pin + "; report-uri='http://foo.com'",
640 &include_subdomains, &hashes, &report_uri));
641 EXPECT_EQ(expect_report_uri, report_uri);
644 TEST_F(HttpSecurityHeadersTest, BogusPinsHeadersSHA256) {
645 TestBogusPinsHeaders(HASH_VALUE_SHA256);
648 TEST_F(HttpSecurityHeadersTest, ValidPKPHeadersSHA256) {
649 TestValidPKPHeaders(HASH_VALUE_SHA256);
652 TEST_F(HttpSecurityHeadersTest, UpdateDynamicPKPOnly) {
653 TransportSecurityState state;
654 TransportSecurityState::STSState static_sts_state;
655 TransportSecurityState::PKPState static_pkp_state;
657 // docs.google.com has preloaded pins.
658 std::string domain = "docs.google.com";
659 state.enable_static_pins_ = true;
660 EXPECT_TRUE(
661 state.GetStaticDomainState(domain, &static_sts_state, &static_pkp_state));
662 EXPECT_GT(static_pkp_state.spki_hashes.size(), 1UL);
663 HashValueVector saved_hashes = static_pkp_state.spki_hashes;
665 // Add a header, which should only update the dynamic state.
666 HashValue good_hash = GetTestHashValue(1, HASH_VALUE_SHA256);
667 HashValue backup_hash = GetTestHashValue(2, HASH_VALUE_SHA256);
668 std::string good_pin = GetTestPin(1, HASH_VALUE_SHA256);
669 std::string backup_pin = GetTestPin(2, HASH_VALUE_SHA256);
670 GURL report_uri("http://google.com");
671 std::string header = "max-age = 10000; " + good_pin + "; " + backup_pin +
672 ";report-uri=\"" + report_uri.spec() + "\"";
674 // Construct a fake SSLInfo that will pass AddHPKPHeader's checks.
675 SSLInfo ssl_info;
676 ssl_info.public_key_hashes.push_back(good_hash);
677 ssl_info.public_key_hashes.push_back(saved_hashes[0]);
678 EXPECT_TRUE(state.AddHPKPHeader(domain, header, ssl_info));
680 // Expect the static state to remain unchanged.
681 TransportSecurityState::STSState new_static_sts_state;
682 TransportSecurityState::PKPState new_static_pkp_state;
683 EXPECT_TRUE(state.GetStaticDomainState(domain, &new_static_sts_state,
684 &new_static_pkp_state));
685 for (size_t i = 0; i < saved_hashes.size(); ++i) {
686 EXPECT_TRUE(
687 HashValuesEqual(saved_hashes[i])(new_static_pkp_state.spki_hashes[i]));
690 // Expect the dynamic state to reflect the header.
691 TransportSecurityState::PKPState dynamic_pkp_state;
692 EXPECT_TRUE(state.GetDynamicPKPState(domain, &dynamic_pkp_state));
693 EXPECT_EQ(2UL, dynamic_pkp_state.spki_hashes.size());
694 EXPECT_EQ(report_uri, dynamic_pkp_state.report_uri);
696 HashValueVector::const_iterator hash = std::find_if(
697 dynamic_pkp_state.spki_hashes.begin(),
698 dynamic_pkp_state.spki_hashes.end(), HashValuesEqual(good_hash));
699 EXPECT_NE(dynamic_pkp_state.spki_hashes.end(), hash);
701 hash = std::find_if(dynamic_pkp_state.spki_hashes.begin(),
702 dynamic_pkp_state.spki_hashes.end(),
703 HashValuesEqual(backup_hash));
704 EXPECT_NE(dynamic_pkp_state.spki_hashes.end(), hash);
706 // Expect the overall state to reflect the header, too.
707 EXPECT_TRUE(state.HasPublicKeyPins(domain));
708 HashValueVector hashes;
709 hashes.push_back(good_hash);
710 std::string failure_log;
711 const bool is_issued_by_known_root = true;
712 HostPortPair domain_port(domain, 443);
713 EXPECT_TRUE(state.CheckPublicKeyPins(
714 domain_port, is_issued_by_known_root, hashes, nullptr, nullptr,
715 TransportSecurityState::DISABLE_PIN_REPORTS, &failure_log));
717 TransportSecurityState::PKPState new_dynamic_pkp_state;
718 EXPECT_TRUE(state.GetDynamicPKPState(domain, &new_dynamic_pkp_state));
719 EXPECT_EQ(2UL, new_dynamic_pkp_state.spki_hashes.size());
720 EXPECT_EQ(report_uri, new_dynamic_pkp_state.report_uri);
722 hash = std::find_if(new_dynamic_pkp_state.spki_hashes.begin(),
723 new_dynamic_pkp_state.spki_hashes.end(),
724 HashValuesEqual(good_hash));
725 EXPECT_NE(new_dynamic_pkp_state.spki_hashes.end(), hash);
727 hash = std::find_if(new_dynamic_pkp_state.spki_hashes.begin(),
728 new_dynamic_pkp_state.spki_hashes.end(),
729 HashValuesEqual(backup_hash));
730 EXPECT_NE(new_dynamic_pkp_state.spki_hashes.end(), hash);
733 TEST_F(HttpSecurityHeadersTest, UpdateDynamicPKPMaxAge0) {
734 TransportSecurityState state;
735 TransportSecurityState::STSState static_sts_state;
736 TransportSecurityState::PKPState static_pkp_state;
738 // docs.google.com has preloaded pins.
739 std::string domain = "docs.google.com";
740 state.enable_static_pins_ = true;
741 ASSERT_TRUE(
742 state.GetStaticDomainState(domain, &static_sts_state, &static_pkp_state));
743 EXPECT_GT(static_pkp_state.spki_hashes.size(), 1UL);
744 HashValueVector saved_hashes = static_pkp_state.spki_hashes;
746 // Add a header, which should only update the dynamic state.
747 HashValue good_hash = GetTestHashValue(1, HASH_VALUE_SHA256);
748 std::string good_pin = GetTestPin(1, HASH_VALUE_SHA256);
749 std::string backup_pin = GetTestPin(2, HASH_VALUE_SHA256);
750 std::string header = "max-age = 10000; " + good_pin + "; " + backup_pin;
752 // Construct a fake SSLInfo that will pass AddHPKPHeader's checks.
753 SSLInfo ssl_info;
754 ssl_info.public_key_hashes.push_back(good_hash);
755 ssl_info.public_key_hashes.push_back(saved_hashes[0]);
756 EXPECT_TRUE(state.AddHPKPHeader(domain, header, ssl_info));
758 // Expect the static state to remain unchanged.
759 TransportSecurityState::STSState new_static_sts_state;
760 TransportSecurityState::PKPState new_static_pkp_state;
761 EXPECT_TRUE(state.GetStaticDomainState(domain, &new_static_sts_state,
762 &new_static_pkp_state));
763 EXPECT_EQ(saved_hashes.size(), new_static_pkp_state.spki_hashes.size());
764 for (size_t i = 0; i < saved_hashes.size(); ++i) {
765 EXPECT_TRUE(
766 HashValuesEqual(saved_hashes[i])(new_static_pkp_state.spki_hashes[i]));
769 // Expect the dynamic state to have pins.
770 TransportSecurityState::PKPState new_dynamic_pkp_state;
771 EXPECT_TRUE(state.GetDynamicPKPState(domain, &new_dynamic_pkp_state));
772 EXPECT_EQ(2UL, new_dynamic_pkp_state.spki_hashes.size());
773 EXPECT_TRUE(new_dynamic_pkp_state.HasPublicKeyPins());
775 // Now set another header with max-age=0, and check that the pins are
776 // cleared in the dynamic state only.
777 header = "max-age = 0; " + good_pin + "; " + backup_pin;
778 EXPECT_TRUE(state.AddHPKPHeader(domain, header, ssl_info));
780 // Expect the static state to remain unchanged.
781 TransportSecurityState::PKPState new_static_pkp_state2;
782 EXPECT_TRUE(state.GetStaticDomainState(domain, &static_sts_state,
783 &new_static_pkp_state2));
784 EXPECT_EQ(saved_hashes.size(), new_static_pkp_state2.spki_hashes.size());
785 for (size_t i = 0; i < saved_hashes.size(); ++i) {
786 EXPECT_TRUE(
787 HashValuesEqual(saved_hashes[i])(new_static_pkp_state2.spki_hashes[i]));
790 // Expect the dynamic pins to be gone.
791 TransportSecurityState::PKPState new_dynamic_pkp_state2;
792 EXPECT_FALSE(state.GetDynamicPKPState(domain, &new_dynamic_pkp_state2));
794 // Expect the exact-matching static policy to continue to apply, even
795 // though dynamic policy has been removed. (This policy may change in the
796 // future, in which case this test must be updated.)
797 EXPECT_TRUE(state.HasPublicKeyPins(domain));
798 EXPECT_TRUE(state.ShouldSSLErrorsBeFatal(domain));
799 std::string failure_log;
801 // Damage the hashes to cause a pin validation failure.
802 new_static_pkp_state2.spki_hashes[0].data()[0] ^= 0x80;
803 new_static_pkp_state2.spki_hashes[1].data()[0] ^= 0x80;
804 new_static_pkp_state2.spki_hashes[2].data()[0] ^= 0x80;
806 const bool is_issued_by_known_root = true;
807 HostPortPair domain_port(domain, 443);
808 EXPECT_FALSE(state.CheckPublicKeyPins(
809 domain_port, is_issued_by_known_root, new_static_pkp_state2.spki_hashes,
810 nullptr, nullptr, TransportSecurityState::DISABLE_PIN_REPORTS,
811 &failure_log));
812 EXPECT_NE(0UL, failure_log.length());
815 // Tests that when a static HSTS and a static HPKP entry are present, adding a
816 // dynamic HSTS header does not clobber the static HPKP entry. Further, adding a
817 // dynamic HPKP entry could not affect the HSTS entry for the site.
818 TEST_F(HttpSecurityHeadersTest, NoClobberPins) {
819 TransportSecurityState state;
820 TransportSecurityState::STSState sts_state;
821 TransportSecurityState::PKPState pkp_state;
823 // accounts.google.com has preloaded pins.
824 std::string domain = "accounts.google.com";
825 state.enable_static_pins_ = true;
827 // Retrieve the static STS and PKP states as it is by default, including its
828 // known good pins.
829 EXPECT_TRUE(state.GetStaticDomainState(domain, &sts_state, &pkp_state));
830 HashValueVector saved_hashes = pkp_state.spki_hashes;
831 EXPECT_TRUE(sts_state.ShouldUpgradeToSSL());
832 EXPECT_TRUE(pkp_state.HasPublicKeyPins());
833 EXPECT_TRUE(state.ShouldUpgradeToSSL(domain));
834 EXPECT_TRUE(state.HasPublicKeyPins(domain));
836 // Add a dynamic HSTS header. CheckPublicKeyPins should still pass when given
837 // the original |saved_hashes|, indicating that the static PKP data is still
838 // configured for the domain.
839 EXPECT_TRUE(state.AddHSTSHeader(domain, "includesubdomains; max-age=10000"));
840 EXPECT_TRUE(state.ShouldUpgradeToSSL(domain));
841 std::string failure_log;
842 const bool is_issued_by_known_root = true;
843 HostPortPair domain_port(domain, 443);
844 EXPECT_TRUE(state.CheckPublicKeyPins(
845 domain_port, is_issued_by_known_root, saved_hashes, nullptr, nullptr,
846 TransportSecurityState::DISABLE_PIN_REPORTS, &failure_log));
848 // Add an HPKP header, which should only update the dynamic state.
849 HashValue good_hash = GetTestHashValue(1, HASH_VALUE_SHA256);
850 std::string good_pin = GetTestPin(1, HASH_VALUE_SHA256);
851 std::string backup_pin = GetTestPin(2, HASH_VALUE_SHA256);
852 std::string header = "max-age = 10000; " + good_pin + "; " + backup_pin;
854 // Construct a fake SSLInfo that will pass AddHPKPHeader's checks.
855 SSLInfo ssl_info;
856 ssl_info.public_key_hashes.push_back(good_hash);
857 ssl_info.public_key_hashes.push_back(saved_hashes[0]);
858 EXPECT_TRUE(state.AddHPKPHeader(domain, header, ssl_info));
860 EXPECT_TRUE(state.AddHPKPHeader(domain, header, ssl_info));
861 // HSTS should still be configured for this domain.
862 EXPECT_TRUE(sts_state.ShouldUpgradeToSSL());
863 EXPECT_TRUE(state.ShouldUpgradeToSSL(domain));
864 // The dynamic pins, which do not match |saved_hashes|, should take
865 // precedence over the static pins and cause the check to fail.
866 EXPECT_FALSE(state.CheckPublicKeyPins(
867 domain_port, is_issued_by_known_root, saved_hashes, nullptr, nullptr,
868 TransportSecurityState::DISABLE_PIN_REPORTS, &failure_log));
871 // Tests that seeing an invalid HPKP header leaves the existing one alone.
872 TEST_F(HttpSecurityHeadersTest, IgnoreInvalidHeaders) {
873 TransportSecurityState state;
875 HashValue good_hash = GetTestHashValue(1, HASH_VALUE_SHA256);
876 std::string good_pin = GetTestPin(1, HASH_VALUE_SHA256);
877 std::string bad_pin = GetTestPin(2, HASH_VALUE_SHA256);
878 std::string backup_pin = GetTestPin(3, HASH_VALUE_SHA256);
880 SSLInfo ssl_info;
881 ssl_info.public_key_hashes.push_back(good_hash);
883 // Add a valid HPKP header.
884 EXPECT_TRUE(state.AddHPKPHeader(
885 "example.com", "max-age = 10000; " + good_pin + "; " + backup_pin,
886 ssl_info));
888 // Check the insertion was valid.
889 EXPECT_TRUE(state.HasPublicKeyPins("example.com"));
890 std::string failure_log;
891 bool is_issued_by_known_root = true;
892 HostPortPair domain_port("example.com", 443);
893 EXPECT_TRUE(state.CheckPublicKeyPins(
894 domain_port, is_issued_by_known_root, ssl_info.public_key_hashes, nullptr,
895 nullptr, TransportSecurityState::DISABLE_PIN_REPORTS, &failure_log));
897 // Now assert an invalid one. This should fail.
898 EXPECT_FALSE(state.AddHPKPHeader(
899 "example.com", "max-age = 10000; " + bad_pin + "; " + backup_pin,
900 ssl_info));
902 // The old pins must still exist.
903 EXPECT_TRUE(state.HasPublicKeyPins("example.com"));
904 EXPECT_TRUE(state.CheckPublicKeyPins(
905 domain_port, is_issued_by_known_root, ssl_info.public_key_hashes, nullptr,
906 nullptr, TransportSecurityState::DISABLE_PIN_REPORTS, &failure_log));
909 }; // namespace net