http_security_headers_unittest.cc revision f2477e01787aa58f445919b809d89e252beef54f
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.
4
5#include <algorithm>
6
7#include "base/base64.h"
8#include "base/sha1.h"
9#include "base/strings/string_piece.h"
10#include "crypto/sha2.h"
11#include "net/base/net_log.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/ssl/ssl_info.h"
17#include "testing/gtest/include/gtest/gtest.h"
18
19namespace net {
20
21namespace {
22
23HashValue GetTestHashValue(uint8 label, HashValueTag tag) {
24  HashValue hash_value(tag);
25  memset(hash_value.data(), label, hash_value.size());
26  return hash_value;
27}
28
29std::string GetTestPin(uint8 label, HashValueTag tag) {
30  HashValue hash_value = GetTestHashValue(label, tag);
31  std::string base64;
32  base::Base64Encode(base::StringPiece(
33      reinterpret_cast<char*>(hash_value.data()), hash_value.size()), &base64);
34
35  switch (hash_value.tag) {
36    case HASH_VALUE_SHA1:
37      return std::string("pin-sha1=\"") + base64 + "\"";
38    case HASH_VALUE_SHA256:
39      return std::string("pin-sha256=\"") + base64 + "\"";
40    default:
41      NOTREACHED() << "Unknown HashValueTag " << hash_value.tag;
42      return std::string("ERROR");
43  }
44}
45
46};
47
48
49class HttpSecurityHeadersTest : public testing::Test {
50};
51
52
53TEST_F(HttpSecurityHeadersTest, BogusHeaders) {
54  base::TimeDelta max_age;
55  bool include_subdomains = false;
56
57  EXPECT_FALSE(
58      ParseHSTSHeader(std::string(), &max_age, &include_subdomains));
59  EXPECT_FALSE(ParseHSTSHeader("    ", &max_age, &include_subdomains));
60  EXPECT_FALSE(ParseHSTSHeader("abc", &max_age, &include_subdomains));
61  EXPECT_FALSE(ParseHSTSHeader("  abc", &max_age, &include_subdomains));
62  EXPECT_FALSE(ParseHSTSHeader("  abc   ", &max_age, &include_subdomains));
63  EXPECT_FALSE(ParseHSTSHeader("max-age", &max_age, &include_subdomains));
64  EXPECT_FALSE(ParseHSTSHeader("  max-age", &max_age,
65                               &include_subdomains));
66  EXPECT_FALSE(ParseHSTSHeader("  max-age  ", &max_age,
67                               &include_subdomains));
68  EXPECT_FALSE(ParseHSTSHeader("max-age=", &max_age, &include_subdomains));
69  EXPECT_FALSE(ParseHSTSHeader("   max-age=", &max_age,
70                               &include_subdomains));
71  EXPECT_FALSE(ParseHSTSHeader("   max-age  =", &max_age,
72                               &include_subdomains));
73  EXPECT_FALSE(ParseHSTSHeader("   max-age=   ", &max_age,
74                               &include_subdomains));
75  EXPECT_FALSE(ParseHSTSHeader("   max-age  =     ", &max_age,
76                               &include_subdomains));
77  EXPECT_FALSE(ParseHSTSHeader("   max-age  =     xy", &max_age,
78                               &include_subdomains));
79  EXPECT_FALSE(ParseHSTSHeader("   max-age  =     3488a923", &max_age,
80                               &include_subdomains));
81  EXPECT_FALSE(ParseHSTSHeader("max-age=3488a923  ", &max_age,
82                               &include_subdomains));
83  EXPECT_FALSE(ParseHSTSHeader("max-ag=3488923", &max_age,
84                               &include_subdomains));
85  EXPECT_FALSE(ParseHSTSHeader("max-aged=3488923", &max_age,
86                               &include_subdomains));
87  EXPECT_FALSE(ParseHSTSHeader("max-age==3488923", &max_age,
88                               &include_subdomains));
89  EXPECT_FALSE(ParseHSTSHeader("amax-age=3488923", &max_age,
90                               &include_subdomains));
91  EXPECT_FALSE(ParseHSTSHeader("max-age=-3488923", &max_age,
92                               &include_subdomains));
93  EXPECT_FALSE(ParseHSTSHeader("max-age=3488923;", &max_age,
94                               &include_subdomains));
95  EXPECT_FALSE(ParseHSTSHeader("max-age=3488923     e", &max_age,
96                               &include_subdomains));
97  EXPECT_FALSE(ParseHSTSHeader("max-age=3488923     includesubdomain",
98                               &max_age, &include_subdomains));
99  EXPECT_FALSE(ParseHSTSHeader("max-age=3488923includesubdomains",
100                               &max_age, &include_subdomains));
101  EXPECT_FALSE(ParseHSTSHeader("max-age=3488923=includesubdomains",
102                               &max_age, &include_subdomains));
103  EXPECT_FALSE(ParseHSTSHeader("max-age=3488923 includesubdomainx",
104                               &max_age, &include_subdomains));
105  EXPECT_FALSE(ParseHSTSHeader("max-age=3488923 includesubdomain=",
106                               &max_age, &include_subdomains));
107  EXPECT_FALSE(ParseHSTSHeader("max-age=3488923 includesubdomain=true",
108                               &max_age, &include_subdomains));
109  EXPECT_FALSE(ParseHSTSHeader("max-age=3488923 includesubdomainsx",
110                               &max_age, &include_subdomains));
111  EXPECT_FALSE(ParseHSTSHeader("max-age=3488923 includesubdomains x",
112                               &max_age, &include_subdomains));
113  EXPECT_FALSE(ParseHSTSHeader("max-age=34889.23 includesubdomains",
114                               &max_age, &include_subdomains));
115  EXPECT_FALSE(ParseHSTSHeader("max-age=34889 includesubdomains",
116                               &max_age, &include_subdomains));
117
118  // Check the out args were not updated by checking the default
119  // values for its predictable fields.
120  EXPECT_EQ(0, max_age.InSeconds());
121  EXPECT_FALSE(include_subdomains);
122}
123
124static void TestBogusPinsHeaders(HashValueTag tag) {
125  base::TimeDelta max_age;
126  bool include_subdomains;
127  HashValueVector hashes;
128  HashValueVector chain_hashes;
129
130  // Set some fake "chain" hashes
131  chain_hashes.push_back(GetTestHashValue(1, tag));
132  chain_hashes.push_back(GetTestHashValue(2, tag));
133  chain_hashes.push_back(GetTestHashValue(3, tag));
134
135  // The good pin must be in the chain, the backup pin must not be
136  std::string good_pin = GetTestPin(2, tag);
137  std::string backup_pin = GetTestPin(4, tag);
138
139  EXPECT_FALSE(ParseHPKPHeader(std::string(), chain_hashes, &max_age,
140                               &include_subdomains, &hashes));
141  EXPECT_FALSE(ParseHPKPHeader("    ", chain_hashes, &max_age,
142                               &include_subdomains, &hashes));
143  EXPECT_FALSE(ParseHPKPHeader("abc", chain_hashes, &max_age,
144                               &include_subdomains, &hashes));
145  EXPECT_FALSE(ParseHPKPHeader("  abc", chain_hashes, &max_age,
146                               &include_subdomains, &hashes));
147  EXPECT_FALSE(ParseHPKPHeader("  abc   ", chain_hashes, &max_age,
148                               &include_subdomains, &hashes));
149  EXPECT_FALSE(ParseHPKPHeader("max-age", chain_hashes, &max_age,
150                               &include_subdomains, &hashes));
151  EXPECT_FALSE(ParseHPKPHeader("  max-age", chain_hashes, &max_age,
152                               &include_subdomains, &hashes));
153  EXPECT_FALSE(ParseHPKPHeader("  max-age  ", chain_hashes, &max_age,
154                               &include_subdomains, &hashes));
155  EXPECT_FALSE(ParseHPKPHeader("max-age=", chain_hashes, &max_age,
156                               &include_subdomains, &hashes));
157  EXPECT_FALSE(ParseHPKPHeader("   max-age=", chain_hashes, &max_age,
158                               &include_subdomains, &hashes));
159  EXPECT_FALSE(ParseHPKPHeader("   max-age  =", chain_hashes, &max_age,
160                               &include_subdomains, &hashes));
161  EXPECT_FALSE(ParseHPKPHeader("   max-age=   ", chain_hashes, &max_age,
162                               &include_subdomains, &hashes));
163  EXPECT_FALSE(ParseHPKPHeader("   max-age  =     ", chain_hashes,
164                               &max_age, &include_subdomains, &hashes));
165  EXPECT_FALSE(ParseHPKPHeader("   max-age  =     xy", chain_hashes,
166                               &max_age, &include_subdomains, &hashes));
167  EXPECT_FALSE(ParseHPKPHeader("   max-age  =     3488a923",
168                               chain_hashes, &max_age, &include_subdomains,
169                               &hashes));
170  EXPECT_FALSE(ParseHPKPHeader("max-age=3488a923  ", chain_hashes,
171                               &max_age, &include_subdomains, &hashes));
172  EXPECT_FALSE(ParseHPKPHeader("max-ag=3488923pins=" + good_pin + "," +
173                               backup_pin,
174                               chain_hashes, &max_age, &include_subdomains,
175                               &hashes));
176  EXPECT_FALSE(ParseHPKPHeader("max-aged=3488923" + backup_pin,
177                               chain_hashes, &max_age, &include_subdomains,
178                               &hashes));
179  EXPECT_FALSE(ParseHPKPHeader("max-aged=3488923; " + backup_pin,
180                               chain_hashes, &max_age, &include_subdomains,
181                               &hashes));
182  EXPECT_FALSE(ParseHPKPHeader("max-aged=3488923; " + backup_pin + ";" +
183                               backup_pin,
184                               chain_hashes, &max_age, &include_subdomains,
185                               &hashes));
186  EXPECT_FALSE(ParseHPKPHeader("max-aged=3488923; " + good_pin + ";" +
187                               good_pin,
188                               chain_hashes, &max_age, &include_subdomains,
189                               &hashes));
190  EXPECT_FALSE(ParseHPKPHeader("max-aged=3488923; " + good_pin,
191                               chain_hashes, &max_age, &include_subdomains,
192                               &hashes));
193  EXPECT_FALSE(ParseHPKPHeader("max-age==3488923", chain_hashes, &max_age,
194                               &include_subdomains, &hashes));
195  EXPECT_FALSE(ParseHPKPHeader("amax-age=3488923", chain_hashes, &max_age,
196                               &include_subdomains, &hashes));
197  EXPECT_FALSE(ParseHPKPHeader("max-age=-3488923", chain_hashes, &max_age,
198                               &include_subdomains, &hashes));
199  EXPECT_FALSE(ParseHPKPHeader("max-age=3488923;", chain_hashes, &max_age,
200                               &include_subdomains, &hashes));
201  EXPECT_FALSE(ParseHPKPHeader("max-age=3488923     e", chain_hashes,
202                               &max_age, &include_subdomains, &hashes));
203  EXPECT_FALSE(ParseHPKPHeader("max-age=3488923     includesubdomain",
204                               chain_hashes, &max_age, &include_subdomains,
205                               &hashes));
206  EXPECT_FALSE(ParseHPKPHeader("max-age=34889.23", chain_hashes, &max_age,
207                               &include_subdomains, &hashes));
208
209  // Check the out args were not updated by checking the default
210  // values for its predictable fields.
211  EXPECT_EQ(0, max_age.InSeconds());
212  EXPECT_EQ(hashes.size(), (size_t)0);
213}
214
215TEST_F(HttpSecurityHeadersTest, ValidSTSHeaders) {
216  base::TimeDelta max_age;
217  base::TimeDelta expect_max_age;
218  bool include_subdomains = false;
219
220  EXPECT_TRUE(ParseHSTSHeader("max-age=243", &max_age,
221                              &include_subdomains));
222  expect_max_age = base::TimeDelta::FromSeconds(243);
223  EXPECT_EQ(expect_max_age, max_age);
224  EXPECT_FALSE(include_subdomains);
225
226  EXPECT_TRUE(ParseHSTSHeader("  Max-agE    = 567", &max_age,
227                              &include_subdomains));
228  expect_max_age = base::TimeDelta::FromSeconds(567);
229  EXPECT_EQ(expect_max_age, max_age);
230  EXPECT_FALSE(include_subdomains);
231
232  EXPECT_TRUE(ParseHSTSHeader("  mAx-aGe    = 890      ", &max_age,
233                              &include_subdomains));
234  expect_max_age = base::TimeDelta::FromSeconds(890);
235  EXPECT_EQ(expect_max_age, max_age);
236  EXPECT_FALSE(include_subdomains);
237
238  EXPECT_TRUE(ParseHSTSHeader("max-age=123;incLudesUbdOmains", &max_age,
239                              &include_subdomains));
240  expect_max_age = base::TimeDelta::FromSeconds(123);
241  EXPECT_EQ(expect_max_age, max_age);
242  EXPECT_TRUE(include_subdomains);
243
244  EXPECT_TRUE(ParseHSTSHeader("incLudesUbdOmains; max-age=123", &max_age,
245                              &include_subdomains));
246  expect_max_age = base::TimeDelta::FromSeconds(123);
247  EXPECT_EQ(expect_max_age, max_age);
248  EXPECT_TRUE(include_subdomains);
249
250  EXPECT_TRUE(ParseHSTSHeader("   incLudesUbdOmains; max-age=123",
251                              &max_age, &include_subdomains));
252  expect_max_age = base::TimeDelta::FromSeconds(123);
253  EXPECT_EQ(expect_max_age, max_age);
254  EXPECT_TRUE(include_subdomains);
255
256  EXPECT_TRUE(ParseHSTSHeader(
257      "   incLudesUbdOmains; max-age=123; pumpkin=kitten", &max_age,
258                                   &include_subdomains));
259  expect_max_age = base::TimeDelta::FromSeconds(123);
260  EXPECT_EQ(expect_max_age, max_age);
261  EXPECT_TRUE(include_subdomains);
262
263  EXPECT_TRUE(ParseHSTSHeader(
264      "   pumpkin=894; incLudesUbdOmains; max-age=123  ", &max_age,
265                                   &include_subdomains));
266  expect_max_age = base::TimeDelta::FromSeconds(123);
267  EXPECT_EQ(expect_max_age, max_age);
268  EXPECT_TRUE(include_subdomains);
269
270  EXPECT_TRUE(ParseHSTSHeader(
271      "   pumpkin; incLudesUbdOmains; max-age=123  ", &max_age,
272                                   &include_subdomains));
273  expect_max_age = base::TimeDelta::FromSeconds(123);
274  EXPECT_EQ(expect_max_age, max_age);
275  EXPECT_TRUE(include_subdomains);
276
277  EXPECT_TRUE(ParseHSTSHeader(
278      "   pumpkin; incLudesUbdOmains; max-age=\"123\"  ", &max_age,
279                                   &include_subdomains));
280  expect_max_age = base::TimeDelta::FromSeconds(123);
281  EXPECT_EQ(expect_max_age, max_age);
282  EXPECT_TRUE(include_subdomains);
283
284  EXPECT_TRUE(ParseHSTSHeader(
285      "animal=\"squirrel; distinguished\"; incLudesUbdOmains; max-age=123",
286                                   &max_age, &include_subdomains));
287  expect_max_age = base::TimeDelta::FromSeconds(123);
288  EXPECT_EQ(expect_max_age, max_age);
289  EXPECT_TRUE(include_subdomains);
290
291  EXPECT_TRUE(ParseHSTSHeader("max-age=394082;  incLudesUbdOmains",
292                              &max_age, &include_subdomains));
293  expect_max_age = base::TimeDelta::FromSeconds(394082);
294  EXPECT_EQ(expect_max_age, max_age);
295  EXPECT_TRUE(include_subdomains);
296
297  EXPECT_TRUE(ParseHSTSHeader(
298      "max-age=39408299  ;incLudesUbdOmains", &max_age,
299      &include_subdomains));
300  expect_max_age = base::TimeDelta::FromSeconds(
301      std::min(kMaxHSTSAgeSecs, static_cast<int64>(GG_INT64_C(39408299))));
302  EXPECT_EQ(expect_max_age, max_age);
303  EXPECT_TRUE(include_subdomains);
304
305  EXPECT_TRUE(ParseHSTSHeader(
306      "max-age=394082038  ; incLudesUbdOmains", &max_age,
307      &include_subdomains));
308  expect_max_age = base::TimeDelta::FromSeconds(
309      std::min(kMaxHSTSAgeSecs, static_cast<int64>(GG_INT64_C(394082038))));
310  EXPECT_EQ(expect_max_age, max_age);
311  EXPECT_TRUE(include_subdomains);
312
313  EXPECT_TRUE(ParseHSTSHeader(
314      "  max-age=0  ;  incLudesUbdOmains   ", &max_age,
315      &include_subdomains));
316  expect_max_age = base::TimeDelta::FromSeconds(0);
317  EXPECT_EQ(expect_max_age, max_age);
318  EXPECT_TRUE(include_subdomains);
319
320  EXPECT_TRUE(ParseHSTSHeader(
321      "  max-age=999999999999999999999999999999999999999999999  ;"
322      "  incLudesUbdOmains   ", &max_age, &include_subdomains));
323  expect_max_age = base::TimeDelta::FromSeconds(
324      kMaxHSTSAgeSecs);
325  EXPECT_EQ(expect_max_age, max_age);
326  EXPECT_TRUE(include_subdomains);
327}
328
329static void TestValidPKPHeaders(HashValueTag tag) {
330  base::TimeDelta max_age;
331  base::TimeDelta expect_max_age;
332  bool include_subdomains;
333  HashValueVector hashes;
334  HashValueVector chain_hashes;
335
336  // Set some fake "chain" hashes into chain_hashes
337  chain_hashes.push_back(GetTestHashValue(1, tag));
338  chain_hashes.push_back(GetTestHashValue(2, tag));
339  chain_hashes.push_back(GetTestHashValue(3, tag));
340
341  // The good pin must be in the chain, the backup pin must not be
342  std::string good_pin = GetTestPin(2, tag);
343  std::string backup_pin = GetTestPin(4, tag);
344
345  EXPECT_TRUE(ParseHPKPHeader(
346      "max-age=243; " + good_pin + ";" + backup_pin,
347      chain_hashes, &max_age, &include_subdomains, &hashes));
348  expect_max_age = base::TimeDelta::FromSeconds(243);
349  EXPECT_EQ(expect_max_age, max_age);
350  EXPECT_FALSE(include_subdomains);
351
352  EXPECT_TRUE(ParseHPKPHeader(
353      "   " + good_pin + "; " + backup_pin + "  ; Max-agE    = 567",
354      chain_hashes, &max_age, &include_subdomains, &hashes));
355  expect_max_age = base::TimeDelta::FromSeconds(567);
356  EXPECT_EQ(expect_max_age, max_age);
357  EXPECT_FALSE(include_subdomains);
358
359  EXPECT_TRUE(ParseHPKPHeader(
360      "includeSubDOMAINS;" + good_pin + ";" + backup_pin +
361      "  ; mAx-aGe    = 890      ",
362      chain_hashes, &max_age, &include_subdomains, &hashes));
363  expect_max_age = base::TimeDelta::FromSeconds(890);
364  EXPECT_EQ(expect_max_age, max_age);
365  EXPECT_TRUE(include_subdomains);
366
367  EXPECT_TRUE(ParseHPKPHeader(
368      good_pin + ";" + backup_pin + "; max-age=123;IGNORED;",
369      chain_hashes, &max_age, &include_subdomains, &hashes));
370  expect_max_age = base::TimeDelta::FromSeconds(123);
371  EXPECT_EQ(expect_max_age, max_age);
372  EXPECT_FALSE(include_subdomains);
373
374  EXPECT_TRUE(ParseHPKPHeader(
375      "max-age=394082;" + backup_pin + ";" + good_pin + ";  ",
376      chain_hashes, &max_age, &include_subdomains, &hashes));
377  expect_max_age = base::TimeDelta::FromSeconds(394082);
378  EXPECT_EQ(expect_max_age, max_age);
379  EXPECT_FALSE(include_subdomains);
380
381  EXPECT_TRUE(ParseHPKPHeader(
382      "max-age=39408299  ;" + backup_pin + ";" + good_pin + ";  ",
383      chain_hashes, &max_age, &include_subdomains, &hashes));
384  expect_max_age = base::TimeDelta::FromSeconds(
385      std::min(kMaxHSTSAgeSecs, static_cast<int64>(GG_INT64_C(39408299))));
386  EXPECT_EQ(expect_max_age, max_age);
387  EXPECT_FALSE(include_subdomains);
388
389  EXPECT_TRUE(ParseHPKPHeader(
390      "max-age=39408038  ;    cybers=39408038  ;  includeSubdomains; " +
391          good_pin + ";" + backup_pin + ";   ",
392      chain_hashes, &max_age, &include_subdomains, &hashes));
393  expect_max_age = base::TimeDelta::FromSeconds(
394      std::min(kMaxHSTSAgeSecs, static_cast<int64>(GG_INT64_C(394082038))));
395  EXPECT_EQ(expect_max_age, max_age);
396  EXPECT_TRUE(include_subdomains);
397
398  EXPECT_TRUE(ParseHPKPHeader(
399      "  max-age=0  ;  " + good_pin + ";" + backup_pin,
400      chain_hashes, &max_age, &include_subdomains, &hashes));
401  expect_max_age = base::TimeDelta::FromSeconds(0);
402  EXPECT_EQ(expect_max_age, max_age);
403  EXPECT_FALSE(include_subdomains);
404
405  EXPECT_TRUE(ParseHPKPHeader(
406      "  max-age=0 ; includeSubdomains;  " + good_pin + ";" + backup_pin,
407      chain_hashes, &max_age, &include_subdomains, &hashes));
408  expect_max_age = base::TimeDelta::FromSeconds(0);
409  EXPECT_EQ(expect_max_age, max_age);
410  EXPECT_TRUE(include_subdomains);
411
412  EXPECT_TRUE(ParseHPKPHeader(
413      "  max-age=999999999999999999999999999999999999999999999  ;  " +
414          backup_pin + ";" + good_pin + ";   ",
415      chain_hashes, &max_age, &include_subdomains, &hashes));
416  expect_max_age = base::TimeDelta::FromSeconds(kMaxHSTSAgeSecs);
417  EXPECT_EQ(expect_max_age, max_age);
418  EXPECT_FALSE(include_subdomains);
419
420  // Test that parsing the same header twice doesn't duplicate the recorded
421  // hashes.
422  hashes.clear();
423  EXPECT_TRUE(ParseHPKPHeader(
424      "  max-age=999;  " +
425          backup_pin + ";" + good_pin + ";   ",
426      chain_hashes, &max_age, &include_subdomains, &hashes));
427  EXPECT_EQ(2u, hashes.size());
428  EXPECT_TRUE(ParseHPKPHeader(
429      "  max-age=999;  " +
430          backup_pin + ";" + good_pin + ";   ",
431      chain_hashes, &max_age, &include_subdomains, &hashes));
432  EXPECT_EQ(2u, hashes.size());
433}
434
435TEST_F(HttpSecurityHeadersTest, BogusPinsHeadersSHA1) {
436  TestBogusPinsHeaders(HASH_VALUE_SHA1);
437}
438
439TEST_F(HttpSecurityHeadersTest, BogusPinsHeadersSHA256) {
440  TestBogusPinsHeaders(HASH_VALUE_SHA256);
441}
442
443TEST_F(HttpSecurityHeadersTest, ValidPKPHeadersSHA1) {
444  TestValidPKPHeaders(HASH_VALUE_SHA1);
445}
446
447TEST_F(HttpSecurityHeadersTest, ValidPKPHeadersSHA256) {
448  TestValidPKPHeaders(HASH_VALUE_SHA256);
449}
450
451TEST_F(HttpSecurityHeadersTest, UpdateDynamicPKPOnly) {
452  TransportSecurityState state;
453  TransportSecurityState::DomainState domain_state;
454
455  // docs.google.com has preloaded pins.
456  std::string domain = "docs.google.com";
457  EXPECT_TRUE(state.GetDomainState(domain, true, &domain_state));
458  EXPECT_GT(domain_state.static_spki_hashes.size(), 1UL);
459  HashValueVector saved_hashes = domain_state.static_spki_hashes;
460
461  // Add a header, which should only update the dynamic state.
462  HashValue good_hash = GetTestHashValue(1, HASH_VALUE_SHA1);
463  HashValue backup_hash = GetTestHashValue(2, HASH_VALUE_SHA1);
464  std::string good_pin = GetTestPin(1, HASH_VALUE_SHA1);
465  std::string backup_pin = GetTestPin(2, HASH_VALUE_SHA1);
466  std::string header = "max-age = 10000; " + good_pin + "; " + backup_pin;
467
468  // Construct a fake SSLInfo that will pass AddHPKPHeader's checks.
469  SSLInfo ssl_info;
470  ssl_info.public_key_hashes.push_back(good_hash);
471  ssl_info.public_key_hashes.push_back(saved_hashes[0]);
472  EXPECT_TRUE(state.AddHPKPHeader(domain, header, ssl_info));
473
474  // Expect the preloaded state to remain unchanged.
475  std::string canonicalized_host = TransportSecurityState::CanonicalizeHost(
476      domain);
477  TransportSecurityState::DomainState static_domain_state;
478  EXPECT_TRUE(state.GetStaticDomainState(canonicalized_host,
479                                         true,
480                                         &static_domain_state));
481  for (size_t i = 0; i < saved_hashes.size(); ++i) {
482    EXPECT_TRUE(HashValuesEqual(
483        saved_hashes[i])(static_domain_state.static_spki_hashes[i]));
484  }
485
486  // Expect the dynamic state to reflect the header.
487  TransportSecurityState::DomainState dynamic_domain_state;
488  EXPECT_TRUE(state.GetDynamicDomainState(domain, &dynamic_domain_state));
489  EXPECT_EQ(2UL, dynamic_domain_state.dynamic_spki_hashes.size());
490
491  HashValueVector::const_iterator hash = std::find_if(
492      dynamic_domain_state.dynamic_spki_hashes.begin(),
493      dynamic_domain_state.dynamic_spki_hashes.end(),
494      HashValuesEqual(good_hash));
495  EXPECT_NE(dynamic_domain_state.dynamic_spki_hashes.end(), hash);
496
497  hash = std::find_if(
498      dynamic_domain_state.dynamic_spki_hashes.begin(),
499      dynamic_domain_state.dynamic_spki_hashes.end(),
500      HashValuesEqual(backup_hash));
501  EXPECT_NE(dynamic_domain_state.dynamic_spki_hashes.end(), hash);
502
503  // Expect the overall state to reflect the header, too.
504  EXPECT_TRUE(state.GetDomainState(domain, true, &domain_state));
505  EXPECT_EQ(2UL, domain_state.dynamic_spki_hashes.size());
506
507  hash = std::find_if(domain_state.dynamic_spki_hashes.begin(),
508                      domain_state.dynamic_spki_hashes.end(),
509                      HashValuesEqual(good_hash));
510  EXPECT_NE(domain_state.dynamic_spki_hashes.end(), hash);
511
512  hash = std::find_if(
513      domain_state.dynamic_spki_hashes.begin(),
514      domain_state.dynamic_spki_hashes.end(),
515      HashValuesEqual(backup_hash));
516  EXPECT_NE(domain_state.dynamic_spki_hashes.end(), hash);
517}
518
519};    // namespace net
520