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 "net/base/transport_security_state.h"
10 #include "base/base64.h"
11 #include "base/file_path.h"
12 #include "base/sha1.h"
13 #include "base/string_piece.h"
14 #include "net/base/asn1_util.h"
15 #include "net/base/cert_test_util.h"
16 #include "net/base/cert_verifier.h"
17 #include "net/base/ssl_info.h"
18 #include "net/base/test_root_certs.h"
19 #include "net/base/x509_certificate.h"
20 #include "net/http/http_util.h"
21 #include "testing/gtest/include/gtest/gtest.h"
23 #if defined(USE_OPENSSL)
24 #include "crypto/openssl_util.h"
26 #include "crypto/nss_util.h"
31 class TransportSecurityStateTest
: public testing::Test
{
32 virtual void SetUp() {
33 #if defined(USE_OPENSSL)
34 crypto::EnsureOpenSSLInit();
36 crypto::EnsureNSSInit();
41 TEST_F(TransportSecurityStateTest
, BogusHeaders
) {
43 bool include_subdomains
= false;
45 EXPECT_FALSE(TransportSecurityState::ParseHeader(
46 "", &max_age
, &include_subdomains
));
47 EXPECT_FALSE(TransportSecurityState::ParseHeader(
48 " ", &max_age
, &include_subdomains
));
49 EXPECT_FALSE(TransportSecurityState::ParseHeader(
50 "abc", &max_age
, &include_subdomains
));
51 EXPECT_FALSE(TransportSecurityState::ParseHeader(
52 " abc", &max_age
, &include_subdomains
));
53 EXPECT_FALSE(TransportSecurityState::ParseHeader(
54 " abc ", &max_age
, &include_subdomains
));
55 EXPECT_FALSE(TransportSecurityState::ParseHeader(
56 "max-age", &max_age
, &include_subdomains
));
57 EXPECT_FALSE(TransportSecurityState::ParseHeader(
58 " max-age", &max_age
, &include_subdomains
));
59 EXPECT_FALSE(TransportSecurityState::ParseHeader(
60 " max-age ", &max_age
, &include_subdomains
));
61 EXPECT_FALSE(TransportSecurityState::ParseHeader(
62 "max-age=", &max_age
, &include_subdomains
));
63 EXPECT_FALSE(TransportSecurityState::ParseHeader(
64 " max-age=", &max_age
, &include_subdomains
));
65 EXPECT_FALSE(TransportSecurityState::ParseHeader(
66 " max-age =", &max_age
, &include_subdomains
));
67 EXPECT_FALSE(TransportSecurityState::ParseHeader(
68 " max-age= ", &max_age
, &include_subdomains
));
69 EXPECT_FALSE(TransportSecurityState::ParseHeader(
70 " max-age = ", &max_age
, &include_subdomains
));
71 EXPECT_FALSE(TransportSecurityState::ParseHeader(
72 " max-age = xy", &max_age
, &include_subdomains
));
73 EXPECT_FALSE(TransportSecurityState::ParseHeader(
74 " max-age = 3488a923", &max_age
, &include_subdomains
));
75 EXPECT_FALSE(TransportSecurityState::ParseHeader(
76 "max-age=3488a923 ", &max_age
, &include_subdomains
));
77 EXPECT_FALSE(TransportSecurityState::ParseHeader(
78 "max-ag=3488923", &max_age
, &include_subdomains
));
79 EXPECT_FALSE(TransportSecurityState::ParseHeader(
80 "max-aged=3488923", &max_age
, &include_subdomains
));
81 EXPECT_FALSE(TransportSecurityState::ParseHeader(
82 "max-age==3488923", &max_age
, &include_subdomains
));
83 EXPECT_FALSE(TransportSecurityState::ParseHeader(
84 "amax-age=3488923", &max_age
, &include_subdomains
));
85 EXPECT_FALSE(TransportSecurityState::ParseHeader(
86 "max-age=-3488923", &max_age
, &include_subdomains
));
87 EXPECT_FALSE(TransportSecurityState::ParseHeader(
88 "max-age=3488923;", &max_age
, &include_subdomains
));
89 EXPECT_FALSE(TransportSecurityState::ParseHeader(
90 "max-age=3488923 e", &max_age
, &include_subdomains
));
91 EXPECT_FALSE(TransportSecurityState::ParseHeader(
92 "max-age=3488923 includesubdomain", &max_age
, &include_subdomains
));
93 EXPECT_FALSE(TransportSecurityState::ParseHeader(
94 "max-age=3488923includesubdomains", &max_age
, &include_subdomains
));
95 EXPECT_FALSE(TransportSecurityState::ParseHeader(
96 "max-age=3488923=includesubdomains", &max_age
, &include_subdomains
));
97 EXPECT_FALSE(TransportSecurityState::ParseHeader(
98 "max-age=3488923 includesubdomainx", &max_age
, &include_subdomains
));
99 EXPECT_FALSE(TransportSecurityState::ParseHeader(
100 "max-age=3488923 includesubdomain=", &max_age
, &include_subdomains
));
101 EXPECT_FALSE(TransportSecurityState::ParseHeader(
102 "max-age=3488923 includesubdomain=true", &max_age
, &include_subdomains
));
103 EXPECT_FALSE(TransportSecurityState::ParseHeader(
104 "max-age=3488923 includesubdomainsx", &max_age
, &include_subdomains
));
105 EXPECT_FALSE(TransportSecurityState::ParseHeader(
106 "max-age=3488923 includesubdomains x", &max_age
, &include_subdomains
));
107 EXPECT_FALSE(TransportSecurityState::ParseHeader(
108 "max-age=34889.23 includesubdomains", &max_age
, &include_subdomains
));
109 EXPECT_FALSE(TransportSecurityState::ParseHeader(
110 "max-age=34889 includesubdomains", &max_age
, &include_subdomains
));
112 EXPECT_EQ(max_age
, 42);
113 EXPECT_FALSE(include_subdomains
);
116 static std::string
GetPinFromCert(X509Certificate
* cert
) {
117 SHA1Fingerprint spki_hash
;
118 if (!TransportSecurityState::GetPublicKeyHash(*cert
, &spki_hash
))
121 base::Base64Encode(base::StringPiece(reinterpret_cast<char*>(spki_hash
.data
),
122 sizeof(spki_hash
.data
)),
124 return "pin-sha1=" + HttpUtil::Quote(base64
);
127 TEST_F(TransportSecurityStateTest
, BogusPinsHeaders
) {
128 TransportSecurityState::DomainState state
;
132 ImportCertFromFile(GetTestCertsDirectory(), "test_mail_google_com.pem");
133 std::string good_pin
= GetPinFromCert(ssl_info
.cert
);
135 // The backup pin is fake --- it just has to not be in the chain.
136 std::string backup_pin
= "pin-sha1=" +
137 HttpUtil::Quote("6dcfXufJLW3J6S/9rRe4vUlBj5g=");
139 EXPECT_FALSE(TransportSecurityState::ParsePinsHeader(
140 "", ssl_info
, &state
));
141 EXPECT_FALSE(TransportSecurityState::ParsePinsHeader(
142 " ", ssl_info
, &state
));
143 EXPECT_FALSE(TransportSecurityState::ParsePinsHeader(
144 "abc", ssl_info
, &state
));
145 EXPECT_FALSE(TransportSecurityState::ParsePinsHeader(
146 " abc", ssl_info
, &state
));
147 EXPECT_FALSE(TransportSecurityState::ParsePinsHeader(
148 " abc ", ssl_info
, &state
));
149 EXPECT_FALSE(TransportSecurityState::ParsePinsHeader(
150 "max-age", ssl_info
, &state
));
151 EXPECT_FALSE(TransportSecurityState::ParsePinsHeader(
152 " max-age", ssl_info
, &state
));
153 EXPECT_FALSE(TransportSecurityState::ParsePinsHeader(
154 " max-age ", ssl_info
, &state
));
155 EXPECT_FALSE(TransportSecurityState::ParsePinsHeader(
156 "max-age=", ssl_info
, &state
));
157 EXPECT_FALSE(TransportSecurityState::ParsePinsHeader(
158 " max-age=", ssl_info
, &state
));
159 EXPECT_FALSE(TransportSecurityState::ParsePinsHeader(
160 " max-age =", ssl_info
, &state
));
161 EXPECT_FALSE(TransportSecurityState::ParsePinsHeader(
162 " max-age= ", ssl_info
, &state
));
163 EXPECT_FALSE(TransportSecurityState::ParsePinsHeader(
164 " max-age = ", ssl_info
, &state
));
165 EXPECT_FALSE(TransportSecurityState::ParsePinsHeader(
166 " max-age = xy", ssl_info
, &state
));
167 EXPECT_FALSE(TransportSecurityState::ParsePinsHeader(
168 " max-age = 3488a923", ssl_info
, &state
));
169 EXPECT_FALSE(TransportSecurityState::ParsePinsHeader(
170 "max-age=3488a923 ", ssl_info
, &state
));
171 EXPECT_FALSE(TransportSecurityState::ParsePinsHeader(
172 "max-ag=3488923pins=" + good_pin
+ "," + backup_pin
,
174 EXPECT_FALSE(TransportSecurityState::ParsePinsHeader(
175 "max-aged=3488923" + backup_pin
,
177 EXPECT_FALSE(TransportSecurityState::ParsePinsHeader(
178 "max-aged=3488923; " + backup_pin
,
180 EXPECT_FALSE(TransportSecurityState::ParsePinsHeader(
181 "max-aged=3488923; " + backup_pin
+ ";" + backup_pin
,
183 EXPECT_FALSE(TransportSecurityState::ParsePinsHeader(
184 "max-aged=3488923; " + good_pin
+ ";" + good_pin
,
186 EXPECT_FALSE(TransportSecurityState::ParsePinsHeader(
187 "max-aged=3488923; " + good_pin
,
189 EXPECT_FALSE(TransportSecurityState::ParsePinsHeader(
190 "max-age==3488923", ssl_info
, &state
));
191 EXPECT_FALSE(TransportSecurityState::ParsePinsHeader(
192 "amax-age=3488923", ssl_info
, &state
));
193 EXPECT_FALSE(TransportSecurityState::ParsePinsHeader(
194 "max-age=-3488923", ssl_info
, &state
));
195 EXPECT_FALSE(TransportSecurityState::ParsePinsHeader(
196 "max-age=3488923;", ssl_info
, &state
));
197 EXPECT_FALSE(TransportSecurityState::ParsePinsHeader(
198 "max-age=3488923 e", ssl_info
, &state
));
199 EXPECT_FALSE(TransportSecurityState::ParsePinsHeader(
200 "max-age=3488923 includesubdomain", ssl_info
, &state
));
201 EXPECT_FALSE(TransportSecurityState::ParsePinsHeader(
202 "max-age=34889.23", ssl_info
, &state
));
204 EXPECT_EQ(state
.max_age
, 42);
207 TEST_F(TransportSecurityStateTest
, ValidHeaders
) {
209 bool include_subdomains
= true;
211 EXPECT_TRUE(TransportSecurityState::ParseHeader(
212 "max-age=243", &max_age
, &include_subdomains
));
213 EXPECT_EQ(max_age
, 243);
214 EXPECT_FALSE(include_subdomains
);
216 EXPECT_TRUE(TransportSecurityState::ParseHeader(
217 " Max-agE = 567", &max_age
, &include_subdomains
));
218 EXPECT_EQ(max_age
, 567);
219 EXPECT_FALSE(include_subdomains
);
221 EXPECT_TRUE(TransportSecurityState::ParseHeader(
222 " mAx-aGe = 890 ", &max_age
, &include_subdomains
));
223 EXPECT_EQ(max_age
, 890);
224 EXPECT_FALSE(include_subdomains
);
226 EXPECT_TRUE(TransportSecurityState::ParseHeader(
227 "max-age=123;incLudesUbdOmains", &max_age
, &include_subdomains
));
228 EXPECT_EQ(max_age
, 123);
229 EXPECT_TRUE(include_subdomains
);
231 EXPECT_TRUE(TransportSecurityState::ParseHeader(
232 "max-age=394082; incLudesUbdOmains", &max_age
, &include_subdomains
));
233 EXPECT_EQ(max_age
, 394082);
234 EXPECT_TRUE(include_subdomains
);
236 EXPECT_TRUE(TransportSecurityState::ParseHeader(
237 "max-age=39408299 ;incLudesUbdOmains", &max_age
, &include_subdomains
));
239 std::min(TransportSecurityState::kMaxHSTSAgeSecs
, 39408299l));
240 EXPECT_TRUE(include_subdomains
);
242 EXPECT_TRUE(TransportSecurityState::ParseHeader(
243 "max-age=394082038 ; incLudesUbdOmains", &max_age
,
244 &include_subdomains
));
246 std::min(TransportSecurityState::kMaxHSTSAgeSecs
, 394082038l));
247 EXPECT_TRUE(include_subdomains
);
249 EXPECT_TRUE(TransportSecurityState::ParseHeader(
250 " max-age=0 ; incLudesUbdOmains ", &max_age
, &include_subdomains
));
251 EXPECT_EQ(max_age
, 0);
252 EXPECT_TRUE(include_subdomains
);
254 EXPECT_TRUE(TransportSecurityState::ParseHeader(
255 " max-age=999999999999999999999999999999999999999999999 ;"
256 " incLudesUbdOmains ",
257 &max_age
, &include_subdomains
));
258 EXPECT_EQ(max_age
, TransportSecurityState::kMaxHSTSAgeSecs
);
259 EXPECT_TRUE(include_subdomains
);
262 TEST_F(TransportSecurityStateTest
, ValidPinsHeaders
) {
263 TransportSecurityState::DomainState state
;
266 // Set up a realistic SSLInfo with a realistic cert chain.
267 FilePath certs_dir
= GetTestCertsDirectory();
268 scoped_refptr
<X509Certificate
> ee_cert
=
269 ImportCertFromFile(certs_dir
, "2048-rsa-ee-by-2048-rsa-intermediate.pem");
270 ASSERT_NE(static_cast<X509Certificate
*>(NULL
), ee_cert
);
271 scoped_refptr
<X509Certificate
> intermediate
=
272 ImportCertFromFile(certs_dir
, "2048-rsa-intermediate.pem");
273 ASSERT_NE(static_cast<X509Certificate
*>(NULL
), intermediate
);
274 X509Certificate::OSCertHandles intermediates
;
275 intermediates
.push_back(intermediate
->os_cert_handle());
277 ssl_info
.cert
= X509Certificate::CreateFromHandle(ee_cert
->os_cert_handle(),
280 // Add the root that signed the intermediate for this test.
281 scoped_refptr
<X509Certificate
> root_cert
=
282 ImportCertFromFile(certs_dir
, "2048-rsa-root.pem");
283 ASSERT_NE(static_cast<X509Certificate
*>(NULL
), root_cert
);
284 TestRootCerts::GetInstance()->Add(root_cert
.get());
286 // Verify has the side-effect of populating public_key_hashes, which
287 // ParsePinsHeader needs. (It wants to check pins against the validated
288 // chain, not just the presented chain.)
289 CertVerifyResult result
;
290 int rv
= ssl_info
.cert
->Verify("127.0.0.1", 0, NULL
, &result
);
292 // Normally, ssl_client_socket_nss would do this, but for a unit test we
294 ssl_info
.public_key_hashes
= result
.public_key_hashes
;
295 std::string good_pin
= GetPinFromCert(ssl_info
.cert
);
297 // The backup pin is fake --- we just need an SPKI hash that does not match
298 // the hash of any SPKI in the certificate chain.
299 std::string backup_pin
= "pin-sha1=" +
300 HttpUtil::Quote("6dcfXufJLW3J6S/9rRe4vUlBj5g=");
302 EXPECT_TRUE(TransportSecurityState::ParsePinsHeader(
303 "max-age=243; " + good_pin
+ ";" + backup_pin
,
305 EXPECT_EQ(state
.max_age
, 243);
307 EXPECT_TRUE(TransportSecurityState::ParsePinsHeader(
308 " " + good_pin
+ "; " + backup_pin
+ " ; Max-agE = 567",
310 EXPECT_EQ(state
.max_age
, 567);
312 EXPECT_TRUE(TransportSecurityState::ParsePinsHeader(
313 good_pin
+ ";" + backup_pin
+ " ; mAx-aGe = 890 ",
315 EXPECT_EQ(state
.max_age
, 890);
317 EXPECT_TRUE(TransportSecurityState::ParsePinsHeader(
318 good_pin
+ ";" + backup_pin
+ "; max-age=123;IGNORED;",
320 EXPECT_EQ(state
.max_age
, 123);
322 EXPECT_TRUE(TransportSecurityState::ParsePinsHeader(
323 "max-age=394082;" + backup_pin
+ ";" + good_pin
+ "; ",
325 EXPECT_EQ(state
.max_age
, 394082);
327 EXPECT_TRUE(TransportSecurityState::ParsePinsHeader(
328 "max-age=39408299 ;" + backup_pin
+ ";" + good_pin
+ "; ",
330 EXPECT_EQ(state
.max_age
,
331 std::min(TransportSecurityState::kMaxHSTSAgeSecs
, 39408299l));
333 EXPECT_TRUE(TransportSecurityState::ParsePinsHeader(
334 "max-age=39408038 ; cybers=39408038 ; " +
335 good_pin
+ ";" + backup_pin
+ "; ",
337 EXPECT_EQ(state
.max_age
,
338 std::min(TransportSecurityState::kMaxHSTSAgeSecs
, 394082038l));
340 EXPECT_TRUE(TransportSecurityState::ParsePinsHeader(
341 " max-age=0 ; " + good_pin
+ ";" + backup_pin
,
343 EXPECT_EQ(state
.max_age
, 0);
345 EXPECT_TRUE(TransportSecurityState::ParsePinsHeader(
346 " max-age=999999999999999999999999999999999999999999999 ; " +
347 backup_pin
+ ";" + good_pin
+ "; ",
349 EXPECT_EQ(state
.max_age
, TransportSecurityState::kMaxHSTSAgeSecs
);
351 TestRootCerts::GetInstance()->Clear();
354 TEST_F(TransportSecurityStateTest
, SimpleMatches
) {
355 TransportSecurityState
state("");
356 TransportSecurityState::DomainState domain_state
;
357 const base::Time
current_time(base::Time::Now());
358 const base::Time expiry
= current_time
+ base::TimeDelta::FromSeconds(1000);
360 EXPECT_FALSE(state
.GetDomainState(&domain_state
, "yahoo.com", true));
361 domain_state
.expiry
= expiry
;
362 state
.EnableHost("yahoo.com", domain_state
);
363 EXPECT_TRUE(state
.GetDomainState(&domain_state
, "yahoo.com", true));
366 TEST_F(TransportSecurityStateTest
, MatchesCase1
) {
367 TransportSecurityState
state("");
368 TransportSecurityState::DomainState domain_state
;
369 const base::Time
current_time(base::Time::Now());
370 const base::Time expiry
= current_time
+ base::TimeDelta::FromSeconds(1000);
372 EXPECT_FALSE(state
.GetDomainState(&domain_state
, "yahoo.com", true));
373 domain_state
.expiry
= expiry
;
374 state
.EnableHost("YAhoo.coM", domain_state
);
375 EXPECT_TRUE(state
.GetDomainState(&domain_state
, "yahoo.com", true));
378 TEST_F(TransportSecurityStateTest
, MatchesCase2
) {
379 TransportSecurityState
state("");
380 TransportSecurityState::DomainState domain_state
;
381 const base::Time
current_time(base::Time::Now());
382 const base::Time expiry
= current_time
+ base::TimeDelta::FromSeconds(1000);
384 EXPECT_FALSE(state
.GetDomainState(&domain_state
, "YAhoo.coM", true));
385 domain_state
.expiry
= expiry
;
386 state
.EnableHost("yahoo.com", domain_state
);
387 EXPECT_TRUE(state
.GetDomainState(&domain_state
, "YAhoo.coM", true));
390 TEST_F(TransportSecurityStateTest
, SubdomainMatches
) {
391 TransportSecurityState
state("");
392 TransportSecurityState::DomainState domain_state
;
393 const base::Time
current_time(base::Time::Now());
394 const base::Time expiry
= current_time
+ base::TimeDelta::FromSeconds(1000);
396 EXPECT_FALSE(state
.GetDomainState(&domain_state
, "yahoo.com", true));
397 domain_state
.expiry
= expiry
;
398 domain_state
.include_subdomains
= true;
399 state
.EnableHost("yahoo.com", domain_state
);
400 EXPECT_TRUE(state
.GetDomainState(&domain_state
, "yahoo.com", true));
401 EXPECT_TRUE(state
.GetDomainState(&domain_state
, "foo.yahoo.com", true));
402 EXPECT_TRUE(state
.GetDomainState(&domain_state
,
405 EXPECT_TRUE(state
.GetDomainState(&domain_state
,
406 "foo.bar.baz.yahoo.com",
408 EXPECT_FALSE(state
.GetDomainState(&domain_state
, "com", true));
411 TEST_F(TransportSecurityStateTest
, Serialise1
) {
412 TransportSecurityState
state("");
415 state
.Serialise(&output
);
416 EXPECT_TRUE(state
.LoadEntries(output
, &dirty
));
420 TEST_F(TransportSecurityStateTest
, Serialise2
) {
421 TransportSecurityState
state("");
422 TransportSecurityState::DomainState domain_state
;
423 const base::Time
current_time(base::Time::Now());
424 const base::Time expiry
= current_time
+ base::TimeDelta::FromSeconds(1000);
426 EXPECT_FALSE(state
.GetDomainState(&domain_state
, "yahoo.com", true));
427 domain_state
.mode
= TransportSecurityState::DomainState::MODE_STRICT
;
428 domain_state
.expiry
= expiry
;
429 domain_state
.include_subdomains
= true;
430 state
.EnableHost("yahoo.com", domain_state
);
434 state
.Serialise(&output
);
435 EXPECT_TRUE(state
.LoadEntries(output
, &dirty
));
437 EXPECT_TRUE(state
.GetDomainState(&domain_state
, "yahoo.com", true));
438 EXPECT_EQ(domain_state
.mode
,
439 TransportSecurityState::DomainState::MODE_STRICT
);
440 EXPECT_TRUE(state
.GetDomainState(&domain_state
, "foo.yahoo.com", true));
441 EXPECT_EQ(domain_state
.mode
,
442 TransportSecurityState::DomainState::MODE_STRICT
);
443 EXPECT_TRUE(state
.GetDomainState(&domain_state
,
446 EXPECT_EQ(domain_state
.mode
,
447 TransportSecurityState::DomainState::MODE_STRICT
);
448 EXPECT_TRUE(state
.GetDomainState(&domain_state
,
449 "foo.bar.baz.yahoo.com",
451 EXPECT_EQ(domain_state
.mode
,
452 TransportSecurityState::DomainState::MODE_STRICT
);
453 EXPECT_FALSE(state
.GetDomainState(&domain_state
, "com", true));
456 TEST_F(TransportSecurityStateTest
, DeleteSince
) {
457 TransportSecurityState
state("");
458 TransportSecurityState::DomainState domain_state
;
459 const base::Time
current_time(base::Time::Now());
460 const base::Time expiry
= current_time
+ base::TimeDelta::FromSeconds(1000);
461 const base::Time older
= current_time
- base::TimeDelta::FromSeconds(1000);
463 EXPECT_FALSE(state
.GetDomainState(&domain_state
, "yahoo.com", true));
464 domain_state
.mode
= TransportSecurityState::DomainState::MODE_STRICT
;
465 domain_state
.expiry
= expiry
;
466 state
.EnableHost("yahoo.com", domain_state
);
468 state
.DeleteSince(expiry
);
469 EXPECT_TRUE(state
.GetDomainState(&domain_state
, "yahoo.com", true));
470 state
.DeleteSince(older
);
471 EXPECT_FALSE(state
.GetDomainState(&domain_state
, "yahoo.com", true));
474 TEST_F(TransportSecurityStateTest
, DeleteHost
) {
475 TransportSecurityState
state("");
476 TransportSecurityState::DomainState domain_state
;
477 const base::Time
current_time(base::Time::Now());
478 const base::Time expiry
= current_time
+ base::TimeDelta::FromSeconds(1000);
479 domain_state
.mode
= TransportSecurityState::DomainState::MODE_STRICT
;
480 domain_state
.expiry
= expiry
;
481 state
.EnableHost("yahoo.com", domain_state
);
483 EXPECT_TRUE(state
.GetDomainState(&domain_state
, "yahoo.com", true));
484 EXPECT_FALSE(state
.GetDomainState(&domain_state
, "example.com", true));
485 EXPECT_TRUE(state
.DeleteHost("yahoo.com"));
486 EXPECT_FALSE(state
.GetDomainState(&domain_state
, "yahoo.com", true));
489 TEST_F(TransportSecurityStateTest
, SerialiseOld
) {
490 TransportSecurityState
state("");
491 // This is an old-style piece of transport state JSON, which has no creation
495 "\"NiyD+3J1r6z1wjl2n1ALBu94Zj9OsEAMo0kCN8js0Uk=\": {"
496 "\"expiry\": 1266815027.983453, "
497 "\"include_subdomains\": false, "
498 "\"mode\": \"strict\" "
502 EXPECT_TRUE(state
.LoadEntries(output
, &dirty
));
506 TEST_F(TransportSecurityStateTest
, IsPreloaded
) {
507 TransportSecurityState
state("");
509 const std::string paypal
=
510 TransportSecurityState::CanonicalizeHost("paypal.com");
511 const std::string www_paypal
=
512 TransportSecurityState::CanonicalizeHost("www.paypal.com");
513 const std::string a_www_paypal
=
514 TransportSecurityState::CanonicalizeHost("a.www.paypal.com");
515 const std::string abc_paypal
=
516 TransportSecurityState::CanonicalizeHost("a.b.c.paypal.com");
517 const std::string example
=
518 TransportSecurityState::CanonicalizeHost("example.com");
519 const std::string aypal
=
520 TransportSecurityState::CanonicalizeHost("aypal.com");
522 TransportSecurityState::DomainState domain_state
;
523 EXPECT_FALSE(state
.IsPreloadedSTS(paypal
, true, &domain_state
));
524 EXPECT_TRUE(state
.IsPreloadedSTS(www_paypal
, true, &domain_state
));
525 EXPECT_FALSE(domain_state
.include_subdomains
);
526 EXPECT_FALSE(state
.IsPreloadedSTS(a_www_paypal
, true, &domain_state
));
527 EXPECT_FALSE(state
.IsPreloadedSTS(abc_paypal
, true, &domain_state
));
528 EXPECT_FALSE(state
.IsPreloadedSTS(example
, true, &domain_state
));
529 EXPECT_FALSE(state
.IsPreloadedSTS(aypal
, true, &domain_state
));
532 TEST_F(TransportSecurityStateTest
, PreloadedDomainSet
) {
533 TransportSecurityState
state("");
534 TransportSecurityState::DomainState domain_state
;
536 // The domain wasn't being set, leading to a blank string in the
537 // chrome://net-internals/#hsts UI. So test that.
538 EXPECT_TRUE(state
.GetDomainState(&domain_state
,
539 "market.android.com",
541 EXPECT_EQ(domain_state
.domain
, "market.android.com");
542 EXPECT_TRUE(state
.GetDomainState(&domain_state
,
543 "sub.market.android.com",
545 EXPECT_EQ(domain_state
.domain
, "market.android.com");
548 static bool ShouldRedirect(const char* hostname
) {
549 TransportSecurityState
state("");
550 TransportSecurityState::DomainState domain_state
;
551 return state
.GetDomainState(&domain_state
, hostname
, true /* SNI ok */) &&
552 domain_state
.ShouldRedirectHTTPToHTTPS();
555 static bool HasState(const char *hostname
) {
556 TransportSecurityState
state("");
557 TransportSecurityState::DomainState domain_state
;
558 return state
.GetDomainState(&domain_state
, hostname
, true /* SNI ok */);
561 static bool HasPins(const char *hostname
) {
562 TransportSecurityState
state("");
563 TransportSecurityState::DomainState domain_state
;
564 return state
.HasPinsForHost(&domain_state
, hostname
, true /* SNI ok */);
567 static bool OnlyPinning(const char *hostname
) {
568 TransportSecurityState
state("");
569 TransportSecurityState::DomainState domain_state
;
570 return state
.HasPinsForHost(&domain_state
, hostname
, true /* SNI ok */) &&
571 !domain_state
.ShouldRedirectHTTPToHTTPS();
574 TEST_F(TransportSecurityStateTest
, Preloaded
) {
575 TransportSecurityState
state("");
576 TransportSecurityState::DomainState domain_state
;
578 // We do more extensive checks for the first domain.
579 EXPECT_TRUE(state
.GetDomainState(&domain_state
, "www.paypal.com", true));
580 EXPECT_EQ(domain_state
.mode
,
581 TransportSecurityState::DomainState::MODE_STRICT
);
582 EXPECT_TRUE(domain_state
.preloaded
);
583 EXPECT_FALSE(domain_state
.include_subdomains
);
585 EXPECT_FALSE(HasState("paypal.com"));
586 EXPECT_FALSE(HasState("www2.paypal.com"));
587 EXPECT_FALSE(HasState("www2.paypal.com"));
591 EXPECT_TRUE(ShouldRedirect("chrome.google.com"));
592 EXPECT_TRUE(ShouldRedirect("checkout.google.com"));
593 EXPECT_TRUE(ShouldRedirect("health.google.com"));
594 EXPECT_TRUE(ShouldRedirect("docs.google.com"));
595 EXPECT_TRUE(ShouldRedirect("sites.google.com"));
596 EXPECT_TRUE(ShouldRedirect("drive.google.com"));
597 EXPECT_TRUE(ShouldRedirect("spreadsheets.google.com"));
598 EXPECT_TRUE(ShouldRedirect("appengine.google.com"));
599 EXPECT_TRUE(ShouldRedirect("market.android.com"));
600 EXPECT_TRUE(ShouldRedirect("encrypted.google.com"));
601 EXPECT_TRUE(ShouldRedirect("accounts.google.com"));
602 EXPECT_TRUE(ShouldRedirect("profiles.google.com"));
603 EXPECT_TRUE(ShouldRedirect("mail.google.com"));
604 EXPECT_TRUE(ShouldRedirect("chatenabled.mail.google.com"));
605 EXPECT_TRUE(ShouldRedirect("talkgadget.google.com"));
606 EXPECT_TRUE(ShouldRedirect("hostedtalkgadget.google.com"));
607 EXPECT_TRUE(ShouldRedirect("talk.google.com"));
608 EXPECT_TRUE(ShouldRedirect("plus.google.com"));
609 EXPECT_TRUE(ShouldRedirect("groups.google.com"));
610 EXPECT_TRUE(ShouldRedirect("ssl.google-analytics.com"));
611 EXPECT_TRUE(ShouldRedirect("gmail.com"));
612 EXPECT_TRUE(ShouldRedirect("www.gmail.com"));
613 EXPECT_TRUE(ShouldRedirect("googlemail.com"));
614 EXPECT_TRUE(ShouldRedirect("www.googlemail.com"));
615 EXPECT_TRUE(ShouldRedirect("googleplex.com"));
616 EXPECT_TRUE(ShouldRedirect("www.googleplex.com"));
617 EXPECT_FALSE(HasState("m.gmail.com"));
618 EXPECT_FALSE(HasState("m.googlemail.com"));
620 EXPECT_TRUE(OnlyPinning("www.google.com"));
621 EXPECT_TRUE(OnlyPinning("foo.google.com"));
622 EXPECT_TRUE(OnlyPinning("google.com"));
623 EXPECT_TRUE(OnlyPinning("www.youtube.com"));
624 EXPECT_TRUE(OnlyPinning("youtube.com"));
625 EXPECT_TRUE(OnlyPinning("i.ytimg.com"));
626 EXPECT_TRUE(OnlyPinning("ytimg.com"));
627 EXPECT_TRUE(OnlyPinning("googleusercontent.com"));
628 EXPECT_TRUE(OnlyPinning("www.googleusercontent.com"));
629 EXPECT_TRUE(OnlyPinning("www.google-analytics.com"));
630 EXPECT_TRUE(OnlyPinning("googleapis.com"));
631 EXPECT_TRUE(OnlyPinning("googleadservices.com"));
632 EXPECT_TRUE(OnlyPinning("googlecode.com"));
633 EXPECT_TRUE(OnlyPinning("appspot.com"));
634 EXPECT_TRUE(OnlyPinning("googlesyndication.com"));
635 EXPECT_TRUE(OnlyPinning("doubleclick.net"));
636 EXPECT_TRUE(OnlyPinning("googlegroups.com"));
638 // Tests for domains that don't work without SNI.
639 EXPECT_FALSE(state
.GetDomainState(&domain_state
, "gmail.com", false));
640 EXPECT_FALSE(state
.GetDomainState(&domain_state
, "www.gmail.com", false));
641 EXPECT_FALSE(state
.GetDomainState(&domain_state
, "m.gmail.com", false));
642 EXPECT_FALSE(state
.GetDomainState(&domain_state
, "googlemail.com", false));
643 EXPECT_FALSE(state
.GetDomainState(&domain_state
,
644 "www.googlemail.com",
646 EXPECT_FALSE(state
.GetDomainState(&domain_state
,
652 EXPECT_TRUE(ShouldRedirect("aladdinschools.appspot.com"));
654 EXPECT_TRUE(ShouldRedirect("ottospora.nl"));
655 EXPECT_TRUE(ShouldRedirect("www.ottospora.nl"));
657 EXPECT_TRUE(ShouldRedirect("www.paycheckrecords.com"));
659 EXPECT_TRUE(ShouldRedirect("lastpass.com"));
660 EXPECT_TRUE(ShouldRedirect("www.lastpass.com"));
661 EXPECT_FALSE(HasState("blog.lastpass.com"));
663 EXPECT_TRUE(ShouldRedirect("keyerror.com"));
664 EXPECT_TRUE(ShouldRedirect("www.keyerror.com"));
666 EXPECT_TRUE(ShouldRedirect("entropia.de"));
667 EXPECT_TRUE(ShouldRedirect("www.entropia.de"));
668 EXPECT_FALSE(HasState("foo.entropia.de"));
670 EXPECT_TRUE(ShouldRedirect("www.elanex.biz"));
671 EXPECT_FALSE(HasState("elanex.biz"));
672 EXPECT_FALSE(HasState("foo.elanex.biz"));
674 EXPECT_TRUE(ShouldRedirect("sunshinepress.org"));
675 EXPECT_TRUE(ShouldRedirect("www.sunshinepress.org"));
676 EXPECT_TRUE(ShouldRedirect("a.b.sunshinepress.org"));
678 EXPECT_TRUE(ShouldRedirect("www.noisebridge.net"));
679 EXPECT_FALSE(HasState("noisebridge.net"));
680 EXPECT_FALSE(HasState("foo.noisebridge.net"));
682 EXPECT_TRUE(ShouldRedirect("neg9.org"));
683 EXPECT_FALSE(HasState("www.neg9.org"));
685 EXPECT_TRUE(ShouldRedirect("riseup.net"));
686 EXPECT_TRUE(ShouldRedirect("foo.riseup.net"));
688 EXPECT_TRUE(ShouldRedirect("factor.cc"));
689 EXPECT_FALSE(HasState("www.factor.cc"));
691 EXPECT_TRUE(ShouldRedirect("members.mayfirst.org"));
692 EXPECT_TRUE(ShouldRedirect("support.mayfirst.org"));
693 EXPECT_TRUE(ShouldRedirect("id.mayfirst.org"));
694 EXPECT_TRUE(ShouldRedirect("lists.mayfirst.org"));
695 EXPECT_FALSE(HasState("www.mayfirst.org"));
697 EXPECT_TRUE(ShouldRedirect("splendidbacon.com"));
698 EXPECT_TRUE(ShouldRedirect("www.splendidbacon.com"));
699 EXPECT_TRUE(ShouldRedirect("foo.splendidbacon.com"));
701 EXPECT_TRUE(ShouldRedirect("romab.com"));
702 EXPECT_TRUE(ShouldRedirect("www.romab.com"));
703 EXPECT_TRUE(ShouldRedirect("foo.romab.com"));
705 EXPECT_TRUE(ShouldRedirect("logentries.com"));
706 EXPECT_TRUE(ShouldRedirect("www.logentries.com"));
707 EXPECT_FALSE(HasState("foo.logentries.com"));
709 EXPECT_TRUE(ShouldRedirect("stripe.com"));
710 EXPECT_TRUE(ShouldRedirect("foo.stripe.com"));
712 EXPECT_TRUE(ShouldRedirect("cloudsecurityalliance.org"));
713 EXPECT_TRUE(ShouldRedirect("foo.cloudsecurityalliance.org"));
715 EXPECT_TRUE(ShouldRedirect("login.sapo.pt"));
716 EXPECT_TRUE(ShouldRedirect("foo.login.sapo.pt"));
718 EXPECT_TRUE(ShouldRedirect("mattmccutchen.net"));
719 EXPECT_TRUE(ShouldRedirect("foo.mattmccutchen.net"));
721 EXPECT_TRUE(ShouldRedirect("betnet.fr"));
722 EXPECT_TRUE(ShouldRedirect("foo.betnet.fr"));
724 EXPECT_TRUE(ShouldRedirect("uprotect.it"));
725 EXPECT_TRUE(ShouldRedirect("foo.uprotect.it"));
727 EXPECT_TRUE(ShouldRedirect("squareup.com"));
728 EXPECT_FALSE(HasState("foo.squareup.com"));
730 EXPECT_TRUE(ShouldRedirect("cert.se"));
731 EXPECT_TRUE(ShouldRedirect("foo.cert.se"));
733 EXPECT_TRUE(ShouldRedirect("crypto.is"));
734 EXPECT_TRUE(ShouldRedirect("foo.crypto.is"));
736 EXPECT_TRUE(ShouldRedirect("simon.butcher.name"));
737 EXPECT_TRUE(ShouldRedirect("foo.simon.butcher.name"));
739 EXPECT_TRUE(ShouldRedirect("linx.net"));
740 EXPECT_TRUE(ShouldRedirect("foo.linx.net"));
742 EXPECT_TRUE(ShouldRedirect("dropcam.com"));
743 EXPECT_TRUE(ShouldRedirect("www.dropcam.com"));
744 EXPECT_FALSE(HasState("foo.dropcam.com"));
746 EXPECT_TRUE(state
.GetDomainState(&domain_state
,
749 EXPECT_FALSE(domain_state
.preloaded_spki_hashes
.empty());
750 EXPECT_TRUE(state
.GetDomainState(&domain_state
,
751 "www.torproject.org",
753 EXPECT_FALSE(domain_state
.preloaded_spki_hashes
.empty());
754 EXPECT_TRUE(state
.GetDomainState(&domain_state
,
755 "check.torproject.org",
757 EXPECT_FALSE(domain_state
.preloaded_spki_hashes
.empty());
758 EXPECT_TRUE(state
.GetDomainState(&domain_state
,
759 "blog.torproject.org",
761 EXPECT_FALSE(domain_state
.preloaded_spki_hashes
.empty());
762 EXPECT_TRUE(ShouldRedirect("ebanking.indovinabank.com.vn"));
763 EXPECT_TRUE(ShouldRedirect("foo.ebanking.indovinabank.com.vn"));
765 EXPECT_TRUE(ShouldRedirect("epoxate.com"));
766 EXPECT_FALSE(HasState("foo.epoxate.com"));
768 EXPECT_TRUE(HasPins("torproject.org"));
769 EXPECT_TRUE(HasPins("www.torproject.org"));
770 EXPECT_TRUE(HasPins("check.torproject.org"));
771 EXPECT_TRUE(HasPins("blog.torproject.org"));
772 EXPECT_FALSE(HasState("foo.torproject.org"));
774 EXPECT_TRUE(ShouldRedirect("www.moneybookers.com"));
775 EXPECT_FALSE(HasState("moneybookers.com"));
777 EXPECT_TRUE(ShouldRedirect("ledgerscope.net"));
778 EXPECT_TRUE(ShouldRedirect("www.ledgerscope.net"));
779 EXPECT_FALSE(HasState("status.ledgerscope.net"));
781 EXPECT_TRUE(ShouldRedirect("kyps.net"));
782 EXPECT_TRUE(ShouldRedirect("www.kyps.net"));
783 EXPECT_FALSE(HasState("foo.kyps.net"));
785 EXPECT_TRUE(ShouldRedirect("foo.app.recurly.com"));
786 EXPECT_TRUE(ShouldRedirect("foo.api.recurly.com"));
788 EXPECT_TRUE(ShouldRedirect("greplin.com"));
789 EXPECT_TRUE(ShouldRedirect("www.greplin.com"));
790 EXPECT_FALSE(HasState("foo.greplin.com"));
792 EXPECT_TRUE(ShouldRedirect("luneta.nearbuysystems.com"));
793 EXPECT_TRUE(ShouldRedirect("foo.luneta.nearbuysystems.com"));
795 EXPECT_TRUE(ShouldRedirect("ubertt.org"));
796 EXPECT_TRUE(ShouldRedirect("foo.ubertt.org"));
798 EXPECT_TRUE(ShouldRedirect("pixi.me"));
799 EXPECT_TRUE(ShouldRedirect("www.pixi.me"));
801 #if defined(OS_CHROMEOS)
802 static const bool kTwitterHSTS
= true;
804 static const bool kTwitterHSTS
= false;
807 EXPECT_EQ(kTwitterHSTS
, ShouldRedirect("twitter.com"));
808 EXPECT_EQ(kTwitterHSTS
, ShouldRedirect("www.twitter.com"));
809 EXPECT_TRUE(HasPins("www.twitter.com"));
812 TEST_F(TransportSecurityStateTest
, LongNames
) {
813 TransportSecurityState
state("");
814 const char kLongName
[] =
815 "lookupByWaveIdHashAndWaveIdIdAndWaveIdDomainAndWaveletIdIdAnd"
816 "WaveletIdDomainAndBlipBlipid";
817 TransportSecurityState::DomainState domain_state
;
818 // Just checks that we don't hit a NOTREACHED.
819 EXPECT_FALSE(state
.GetDomainState(&domain_state
, kLongName
, true));
822 TEST_F(TransportSecurityStateTest
, PublicKeyHashes
) {
823 TransportSecurityState
state("");
824 TransportSecurityState::DomainState domain_state
;
825 EXPECT_FALSE(state
.GetDomainState(&domain_state
, "example.com", false));
826 FingerprintVector hashes
;
827 EXPECT_TRUE(domain_state
.IsChainOfPublicKeysPermitted(hashes
));
829 SHA1Fingerprint hash
;
830 memset(hash
.data
, '1', sizeof(hash
.data
));
831 domain_state
.preloaded_spki_hashes
.push_back(hash
);
833 EXPECT_FALSE(domain_state
.IsChainOfPublicKeysPermitted(hashes
));
834 hashes
.push_back(hash
);
835 EXPECT_TRUE(domain_state
.IsChainOfPublicKeysPermitted(hashes
));
836 hashes
[0].data
[0] = '2';
837 EXPECT_FALSE(domain_state
.IsChainOfPublicKeysPermitted(hashes
));
839 const base::Time
current_time(base::Time::Now());
840 const base::Time expiry
= current_time
+ base::TimeDelta::FromSeconds(1000);
841 domain_state
.expiry
= expiry
;
842 state
.EnableHost("example.com", domain_state
);
844 EXPECT_TRUE(state
.Serialise(&ser
));
846 EXPECT_TRUE(state
.LoadEntries(ser
, &dirty
));
847 EXPECT_TRUE(state
.GetDomainState(&domain_state
, "example.com", false));
848 EXPECT_EQ(1u, domain_state
.preloaded_spki_hashes
.size());
849 EXPECT_EQ(0, memcmp(domain_state
.preloaded_spki_hashes
[0].data
, hash
.data
,
853 TEST_F(TransportSecurityStateTest
, BuiltinCertPins
) {
854 TransportSecurityState
state("");
855 TransportSecurityState::DomainState domain_state
;
856 EXPECT_TRUE(state
.GetDomainState(&domain_state
,
859 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
, "chrome.google.com", true));
860 FingerprintVector hashes
;
861 // This essential checks that a built-in list does exist.
862 EXPECT_FALSE(domain_state
.IsChainOfPublicKeysPermitted(hashes
));
863 EXPECT_FALSE(state
.HasPinsForHost(&domain_state
, "www.paypal.com", true));
865 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
, "docs.google.com", true));
866 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
, "1.docs.google.com", true));
867 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
, "sites.google.com", true));
868 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
, "drive.google.com", true));
869 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
,
870 "spreadsheets.google.com",
872 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
, "health.google.com", true));
873 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
,
874 "checkout.google.com",
876 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
,
877 "appengine.google.com",
879 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
, "market.android.com", true));
880 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
,
881 "encrypted.google.com",
883 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
,
884 "accounts.google.com",
886 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
,
887 "profiles.google.com",
889 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
, "mail.google.com", true));
890 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
,
891 "chatenabled.mail.google.com",
893 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
,
894 "talkgadget.google.com",
896 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
,
897 "hostedtalkgadget.google.com",
899 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
, "talk.google.com", true));
900 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
, "plus.google.com", true));
901 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
, "groups.google.com", true));
903 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
, "ssl.gstatic.com", true));
904 EXPECT_FALSE(state
.HasPinsForHost(&domain_state
, "www.gstatic.com", true));
905 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
,
906 "ssl.google-analytics.com",
908 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
, "www.googleplex.com", true));
910 // Disabled in order to help track down pinning failures --agl
911 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
, "twitter.com", true));
912 EXPECT_FALSE(state
.HasPinsForHost(&domain_state
, "foo.twitter.com", true));
913 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
, "www.twitter.com", true));
914 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
, "api.twitter.com", true));
915 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
, "oauth.twitter.com", true));
916 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
, "mobile.twitter.com", true));
917 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
, "dev.twitter.com", true));
918 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
, "business.twitter.com",
920 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
, "platform.twitter.com",
922 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
, "si0.twimg.com", true));
923 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
, "twimg0-a.akamaihd.net",
927 static bool AddHash(const std::string
& type_and_base64
,
928 FingerprintVector
* out
) {
929 std::string hash_str
;
930 if (type_and_base64
.find("sha1/") == 0 &&
931 base::Base64Decode(type_and_base64
.substr(5, type_and_base64
.size() - 5),
933 hash_str
.size() == base::kSHA1Length
) {
934 SHA1Fingerprint hash
;
935 memcpy(hash
.data
, hash_str
.data(), sizeof(hash
.data
));
936 out
->push_back(hash
);
942 TEST_F(TransportSecurityStateTest
, PinValidationWithRejectedCerts
) {
943 // kGoodPath is plus.google.com via Google Internet Authority.
944 static const char* kGoodPath
[] = {
945 "sha1/4BjDjn8v2lWeUFQnqSs0BgbIcrU=",
946 "sha1/QMVAHW+MuvCLAO3vse6H0AWzuc0=",
947 "sha1/SOZo+SvSspXXR9gjIBBPM5iQn9Q=",
951 // kBadPath is plus.google.com via Trustcenter, which contains a required
952 // certificate (Equifax root), but also an excluded certificate
954 static const char* kBadPath
[] = {
955 "sha1/4BjDjn8v2lWeUFQnqSs0BgbIcrU=",
956 "sha1/gzuEEAB/bkqdQS3EIjk2by7lW+k=",
957 "sha1/SOZo+SvSspXXR9gjIBBPM5iQn9Q=",
961 std::vector
<net::SHA1Fingerprint
> good_hashes
, bad_hashes
;
963 for (size_t i
= 0; kGoodPath
[i
]; i
++) {
964 EXPECT_TRUE(AddHash(kGoodPath
[i
], &good_hashes
));
966 for (size_t i
= 0; kBadPath
[i
]; i
++) {
967 EXPECT_TRUE(AddHash(kBadPath
[i
], &bad_hashes
));
970 TransportSecurityState
state("");
971 TransportSecurityState::DomainState domain_state
;
972 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
, "plus.google.com", true));
974 EXPECT_TRUE(domain_state
.IsChainOfPublicKeysPermitted(good_hashes
));
975 EXPECT_FALSE(domain_state
.IsChainOfPublicKeysPermitted(bad_hashes
));
978 TEST_F(TransportSecurityStateTest
, PinValidationWithoutRejectedCerts
) {
979 // kGoodPath is blog.torproject.org.
980 static const char* kGoodPath
[] = {
981 "sha1/m9lHYJYke9k0GtVZ+bXSQYE8nDI=",
982 "sha1/o5OZxATDsgmwgcIfIWIneMJ0jkw=",
983 "sha1/wHqYaI2J+6sFZAwRfap9ZbjKzE4=",
987 // kBadPath is plus.google.com via Trustcenter, which is utterly wrong for
989 static const char* kBadPath
[] = {
990 "sha1/4BjDjn8v2lWeUFQnqSs0BgbIcrU=",
991 "sha1/gzuEEAB/bkqdQS3EIjk2by7lW+k=",
992 "sha1/SOZo+SvSspXXR9gjIBBPM5iQn9Q=",
996 std::vector
<net::SHA1Fingerprint
> good_hashes
, bad_hashes
;
998 for (size_t i
= 0; kGoodPath
[i
]; i
++) {
999 EXPECT_TRUE(AddHash(kGoodPath
[i
], &good_hashes
));
1001 for (size_t i
= 0; kBadPath
[i
]; i
++) {
1002 EXPECT_TRUE(AddHash(kBadPath
[i
], &bad_hashes
));
1005 TransportSecurityState
state("");
1006 TransportSecurityState::DomainState domain_state
;
1007 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
, "blog.torproject.org", true));
1009 EXPECT_TRUE(domain_state
.IsChainOfPublicKeysPermitted(good_hashes
));
1010 EXPECT_FALSE(domain_state
.IsChainOfPublicKeysPermitted(bad_hashes
));
1013 TEST_F(TransportSecurityStateTest
, OptionalHSTSCertPins
) {
1014 TransportSecurityState
state("");
1015 TransportSecurityState::DomainState domain_state
;
1016 EXPECT_FALSE(ShouldRedirect("www.google-analytics.com"));
1017 EXPECT_FALSE(state
.HasPinsForHost(&domain_state
,
1018 "www.google-analytics.com",
1020 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
,
1021 "www.google-analytics.com",
1023 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
, "google.com", true));
1024 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
, "www.google.com", true));
1025 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
,
1026 "mail-attachment.googleusercontent.com",
1028 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
, "www.youtube.com", true));
1029 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
, "i.ytimg.com", true));
1030 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
, "googleapis.com", true));
1031 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
,
1032 "ajax.googleapis.com",
1034 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
,
1035 "googleadservices.com",
1037 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
,
1038 "pagead2.googleadservices.com",
1040 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
, "googlecode.com", true));
1041 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
,
1042 "kibbles.googlecode.com",
1044 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
, "appspot.com", true));
1045 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
,
1046 "googlesyndication.com",
1048 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
, "doubleclick.net", true));
1049 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
, "ad.doubleclick.net", true));
1050 EXPECT_FALSE(state
.HasPinsForHost(&domain_state
,
1051 "learn.doubleclick.net",
1053 EXPECT_TRUE(state
.HasPinsForHost(&domain_state
, "a.googlegroups.com", true));
1054 EXPECT_FALSE(state
.HasPinsForHost(&domain_state
,
1055 "a.googlegroups.com",
1059 TEST_F(TransportSecurityStateTest
, ForcePreloads
) {
1060 // This is a docs.google.com override.
1061 std::string
preload("{"
1062 "\"4AGT3lHihuMSd5rUj7B4u6At0jlSH3HFePovjPR+oLE=\": {"
1064 "\"expiry\": 2000000000.0,"
1065 "\"include_subdomains\": false,"
1066 "\"mode\": \"pinning-only\""
1069 TransportSecurityState
state(preload
);
1070 TransportSecurityState::DomainState domain_state
;
1071 EXPECT_FALSE(state
.HasPinsForHost(&domain_state
, "docs.google.com", true));
1072 EXPECT_TRUE(state
.GetDomainState(&domain_state
, "docs.google.com", true));
1073 EXPECT_FALSE(domain_state
.ShouldRedirectHTTPToHTTPS());
1076 TEST_F(TransportSecurityStateTest
, OverrideBuiltins
) {
1077 EXPECT_TRUE(HasPins("google.com"));
1078 EXPECT_FALSE(ShouldRedirect("google.com"));
1079 EXPECT_FALSE(ShouldRedirect("www.google.com"));
1081 TransportSecurityState
state("");
1082 TransportSecurityState::DomainState domain_state
;
1083 const base::Time
current_time(base::Time::Now());
1084 const base::Time expiry
= current_time
+ base::TimeDelta::FromSeconds(1000);
1085 domain_state
.expiry
= expiry
;
1086 state
.EnableHost("www.google.com", domain_state
);
1088 EXPECT_TRUE(state
.GetDomainState(&domain_state
, "www.google.com", true));
1091 static const uint8 kSidePinLeafSPKI
[] = {
1092 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
1093 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48, 0x02, 0x41, 0x00, 0xe4,
1094 0x1d, 0xcc, 0xf2, 0x92, 0xe7, 0x7a, 0xc6, 0x36, 0xf7, 0x1a, 0x62, 0x31, 0x7d,
1095 0x37, 0xea, 0x0d, 0xa2, 0xa8, 0x12, 0x2b, 0xc2, 0x1c, 0x82, 0x3e, 0xa5, 0x70,
1096 0x4a, 0x83, 0x5d, 0x9b, 0x84, 0x82, 0x70, 0xa4, 0x88, 0x98, 0x98, 0x41, 0x29,
1097 0x31, 0xcb, 0x6e, 0x2a, 0x54, 0x65, 0x14, 0x60, 0xcc, 0x00, 0xe8, 0x10, 0x30,
1098 0x0a, 0x4a, 0xd1, 0xa7, 0x52, 0xfe, 0x2d, 0x31, 0x2a, 0x1d, 0x0d, 0x02, 0x03,
1102 static const uint8 kSidePinInfo
[] = {
1103 0x01, 0x00, 0x53, 0x50, 0x49, 0x4e, 0xa0, 0x00, 0x03, 0x00, 0x53, 0x49, 0x47,
1104 0x00, 0x50, 0x55, 0x42, 0x4b, 0x41, 0x4c, 0x47, 0x4f, 0x47, 0x00, 0x41, 0x00,
1105 0x04, 0x00, 0x30, 0x45, 0x02, 0x21, 0x00, 0xfb, 0x26, 0xd5, 0xe8, 0x76, 0x35,
1106 0x96, 0x6d, 0x91, 0x9b, 0x5b, 0x27, 0xe6, 0x09, 0x1c, 0x7b, 0x6c, 0xcd, 0xc8,
1107 0x10, 0x25, 0x95, 0xc0, 0xa5, 0xf6, 0x6c, 0x6f, 0xfb, 0x59, 0x1e, 0x2d, 0xf4,
1108 0x02, 0x20, 0x33, 0x0a, 0xf8, 0x8b, 0x3e, 0xc4, 0xca, 0x75, 0x28, 0xdf, 0x5f,
1109 0xab, 0xe4, 0x46, 0xa0, 0xdd, 0x2d, 0xe5, 0xad, 0xc3, 0x81, 0x44, 0x70, 0xb2,
1110 0x10, 0x87, 0xe8, 0xc3, 0xd6, 0x6e, 0x12, 0x5d, 0x04, 0x67, 0x0b, 0x7d, 0xf2,
1111 0x99, 0x75, 0x57, 0x99, 0x3a, 0x98, 0xf8, 0xe4, 0xdf, 0x79, 0xdf, 0x8e, 0x02,
1112 0x2c, 0xbe, 0xd8, 0xfd, 0x75, 0x80, 0x18, 0xb1, 0x6f, 0x43, 0xd9, 0x8a, 0x79,
1113 0xc3, 0x6e, 0x18, 0xdf, 0x79, 0xc0, 0x59, 0xab, 0xd6, 0x77, 0x37, 0x6a, 0x94,
1114 0x5a, 0x7e, 0xfb, 0xa9, 0xc5, 0x54, 0x14, 0x3a, 0x7b, 0x97, 0x17, 0x2a, 0xb6,
1115 0x1e, 0x59, 0x4f, 0x2f, 0xb1, 0x15, 0x1a, 0x34, 0x50, 0x32, 0x35, 0x36,
1118 static const uint8 kSidePinExpectedHash
[20] = {
1119 0xb5, 0x91, 0x66, 0x47, 0x43, 0x16, 0x62, 0x86, 0xd4, 0x1e, 0x5d, 0x36, 0xe1,
1120 0xc4, 0x09, 0x3d, 0x2d, 0x1d, 0xea, 0x1e,
1123 TEST_F(TransportSecurityStateTest
, ParseSidePins
) {
1124 base::StringPiece
leaf_spki(reinterpret_cast<const char*>(kSidePinLeafSPKI
),
1125 sizeof(kSidePinLeafSPKI
));
1126 base::StringPiece
side_info(reinterpret_cast<const char*>(kSidePinInfo
),
1127 sizeof(kSidePinInfo
));
1129 FingerprintVector pub_key_hashes
;
1130 EXPECT_TRUE(TransportSecurityState::ParseSidePin(
1131 leaf_spki
, side_info
, &pub_key_hashes
));
1132 ASSERT_EQ(1u, pub_key_hashes
.size());
1133 EXPECT_EQ(0, memcmp(pub_key_hashes
[0].data
, kSidePinExpectedHash
,
1134 sizeof(kSidePinExpectedHash
)));
1137 TEST_F(TransportSecurityStateTest
, ParseSidePinsFailsWithBadData
) {
1138 uint8 leaf_spki_copy
[sizeof(kSidePinLeafSPKI
)];
1139 memcpy(leaf_spki_copy
, kSidePinLeafSPKI
, sizeof(leaf_spki_copy
));
1141 uint8 side_info_copy
[sizeof(kSidePinInfo
)];
1142 memcpy(side_info_copy
, kSidePinInfo
, sizeof(kSidePinInfo
));
1144 base::StringPiece
leaf_spki(reinterpret_cast<const char*>(leaf_spki_copy
),
1145 sizeof(leaf_spki_copy
));
1146 base::StringPiece
side_info(reinterpret_cast<const char*>(side_info_copy
),
1147 sizeof(side_info_copy
));
1148 FingerprintVector pub_key_hashes
;
1150 // Tweak |leaf_spki| and expect a failure.
1151 leaf_spki_copy
[10] ^= 1;
1152 EXPECT_FALSE(TransportSecurityState::ParseSidePin(
1153 leaf_spki
, side_info
, &pub_key_hashes
));
1154 ASSERT_EQ(0u, pub_key_hashes
.size());
1156 // Undo the change to |leaf_spki| and tweak |side_info|.
1157 leaf_spki_copy
[10] ^= 1;
1158 side_info_copy
[30] ^= 1;
1159 EXPECT_FALSE(TransportSecurityState::ParseSidePin(
1160 leaf_spki
, side_info
, &pub_key_hashes
));
1161 ASSERT_EQ(0u, pub_key_hashes
.size());
1164 TEST_F(TransportSecurityStateTest
, DISABLED_ParseSidePinsFuzz
) {
1165 // Disabled because it's too slow for normal tests. Run manually when
1166 // changing the underlying code.
1168 base::StringPiece
leaf_spki(reinterpret_cast<const char*>(kSidePinLeafSPKI
),
1169 sizeof(kSidePinLeafSPKI
));
1170 uint8 side_info_copy
[sizeof(kSidePinInfo
)];
1171 base::StringPiece
side_info(reinterpret_cast<const char*>(side_info_copy
),
1172 sizeof(side_info_copy
));
1173 FingerprintVector pub_key_hashes
;
1174 static const size_t bit_length
= sizeof(kSidePinInfo
) * 8;
1176 for (size_t bit_to_flip
= 0; bit_to_flip
< bit_length
; bit_to_flip
++) {
1177 memcpy(side_info_copy
, kSidePinInfo
, sizeof(kSidePinInfo
));
1179 size_t byte
= bit_to_flip
>> 3;
1180 size_t bit
= bit_to_flip
& 7;
1181 side_info_copy
[byte
] ^= (1 << bit
);
1183 EXPECT_FALSE(TransportSecurityState::ParseSidePin(
1184 leaf_spki
, side_info
, &pub_key_hashes
));
1185 ASSERT_EQ(0u, pub_key_hashes
.size());
1189 TEST_F(TransportSecurityStateTest
, GooglePinnedProperties
) {
1190 EXPECT_FALSE(TransportSecurityState::IsGooglePinnedProperty(
1191 "www.example.com", true));
1192 EXPECT_FALSE(TransportSecurityState::IsGooglePinnedProperty(
1193 "www.paypal.com", true));
1194 EXPECT_FALSE(TransportSecurityState::IsGooglePinnedProperty(
1195 "mail.twitter.com", true));
1196 EXPECT_FALSE(TransportSecurityState::IsGooglePinnedProperty(
1197 "www.google.com.int", true));
1198 EXPECT_FALSE(TransportSecurityState::IsGooglePinnedProperty(
1199 "jottit.com", true));
1200 // learn.doubleclick.net has a more specific match than
1201 // *.doubleclick.com, and has 0 or NULL for its required certs.
1202 // This test ensures that the exact-match-preferred behavior
1204 EXPECT_FALSE(TransportSecurityState::IsGooglePinnedProperty(
1205 "learn.doubleclick.net", true));
1207 EXPECT_TRUE(TransportSecurityState::IsGooglePinnedProperty(
1208 "encrypted.google.com", true));
1209 EXPECT_TRUE(TransportSecurityState::IsGooglePinnedProperty(
1210 "mail.google.com", true));
1211 EXPECT_TRUE(TransportSecurityState::IsGooglePinnedProperty(
1212 "accounts.google.com", true));
1213 EXPECT_TRUE(TransportSecurityState::IsGooglePinnedProperty(
1214 "doubleclick.net", true));
1215 EXPECT_TRUE(TransportSecurityState::IsGooglePinnedProperty(
1216 "ad.doubleclick.net", true));
1217 EXPECT_TRUE(TransportSecurityState::IsGooglePinnedProperty(
1218 "youtube.com", true));
1219 EXPECT_TRUE(TransportSecurityState::IsGooglePinnedProperty(
1220 "www.profiles.google.com", true));
1221 EXPECT_TRUE(TransportSecurityState::IsGooglePinnedProperty(
1222 "checkout.google.com", true));
1223 EXPECT_TRUE(TransportSecurityState::IsGooglePinnedProperty(
1224 "googleadservices.com", true));
1226 // Test with sni_enabled false:
1227 EXPECT_FALSE(TransportSecurityState::IsGooglePinnedProperty(
1228 "www.example.com", false));
1229 EXPECT_FALSE(TransportSecurityState::IsGooglePinnedProperty(
1230 "www.paypal.com", false));
1231 EXPECT_TRUE(TransportSecurityState::IsGooglePinnedProperty(
1232 "checkout.google.com", false));
1233 EXPECT_TRUE(TransportSecurityState::IsGooglePinnedProperty(
1234 "googleadservices.com", false));
1236 // Test some SNI hosts:
1237 EXPECT_TRUE(TransportSecurityState::IsGooglePinnedProperty(
1238 "gmail.com", true));
1239 EXPECT_TRUE(TransportSecurityState::IsGooglePinnedProperty(
1240 "googlegroups.com", true));
1241 EXPECT_TRUE(TransportSecurityState::IsGooglePinnedProperty(
1242 "www.googlegroups.com", true));
1243 // Expect to fail for SNI hosts when not searching the SNI list:
1244 EXPECT_FALSE(TransportSecurityState::IsGooglePinnedProperty(
1245 "gmail.com", false));
1246 EXPECT_FALSE(TransportSecurityState::IsGooglePinnedProperty(
1247 "googlegroups.com", false));
1248 EXPECT_FALSE(TransportSecurityState::IsGooglePinnedProperty(
1249 "www.googlegroups.com", false));