| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/base/transport_security_state.h" | 5 #include "net/base/transport_security_state.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <string> | 8 #include <string> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| (...skipping 28 matching lines...) Expand all Loading... |
| 39 class TransportSecurityStateTest : public testing::Test { | 39 class TransportSecurityStateTest : public testing::Test { |
| 40 virtual void SetUp() { | 40 virtual void SetUp() { |
| 41 #if defined(USE_OPENSSL) | 41 #if defined(USE_OPENSSL) |
| 42 crypto::EnsureOpenSSLInit(); | 42 crypto::EnsureOpenSSLInit(); |
| 43 #else | 43 #else |
| 44 crypto::EnsureNSSInit(); | 44 crypto::EnsureNSSInit(); |
| 45 #endif | 45 #endif |
| 46 } | 46 } |
| 47 }; | 47 }; |
| 48 | 48 |
| 49 TEST_F(TransportSecurityStateTest, BogusHeaders) { | |
| 50 TransportSecurityState::DomainState state; | |
| 51 base::Time now = base::Time::Now(); | |
| 52 | |
| 53 EXPECT_FALSE(state.ParseSTSHeader(now, "")); | |
| 54 EXPECT_FALSE(state.ParseSTSHeader(now, " ")); | |
| 55 EXPECT_FALSE(state.ParseSTSHeader(now, "abc")); | |
| 56 EXPECT_FALSE(state.ParseSTSHeader(now, " abc")); | |
| 57 EXPECT_FALSE(state.ParseSTSHeader(now, " abc ")); | |
| 58 EXPECT_FALSE(state.ParseSTSHeader(now, "max-age")); | |
| 59 EXPECT_FALSE(state.ParseSTSHeader(now, " max-age")); | |
| 60 EXPECT_FALSE(state.ParseSTSHeader(now, " max-age ")); | |
| 61 EXPECT_FALSE(state.ParseSTSHeader(now, "max-age=")); | |
| 62 EXPECT_FALSE(state.ParseSTSHeader(now, " max-age=")); | |
| 63 EXPECT_FALSE(state.ParseSTSHeader(now, " max-age =")); | |
| 64 EXPECT_FALSE(state.ParseSTSHeader(now, " max-age= ")); | |
| 65 EXPECT_FALSE(state.ParseSTSHeader(now, " max-age = ")); | |
| 66 EXPECT_FALSE(state.ParseSTSHeader(now, " max-age = xy")); | |
| 67 EXPECT_FALSE(state.ParseSTSHeader(now, " max-age = 3488a923")); | |
| 68 EXPECT_FALSE(state.ParseSTSHeader(now, "max-age=3488a923 ")); | |
| 69 EXPECT_FALSE(state.ParseSTSHeader(now, "max-ag=3488923")); | |
| 70 EXPECT_FALSE(state.ParseSTSHeader(now, "max-aged=3488923")); | |
| 71 EXPECT_FALSE(state.ParseSTSHeader(now, "max-age==3488923")); | |
| 72 EXPECT_FALSE(state.ParseSTSHeader(now, "amax-age=3488923")); | |
| 73 EXPECT_FALSE(state.ParseSTSHeader(now, "max-age=-3488923")); | |
| 74 EXPECT_FALSE(state.ParseSTSHeader(now, "max-age=3488923;")); | |
| 75 EXPECT_FALSE(state.ParseSTSHeader(now, "max-age=3488923 e")); | |
| 76 EXPECT_FALSE(state.ParseSTSHeader( | |
| 77 now, "max-age=3488923 includesubdomain")); | |
| 78 EXPECT_FALSE(state.ParseSTSHeader(now, "max-age=3488923includesubdomains")); | |
| 79 EXPECT_FALSE(state.ParseSTSHeader(now, "max-age=3488923=includesubdomains")); | |
| 80 EXPECT_FALSE(state.ParseSTSHeader(now, "max-age=3488923 includesubdomainx")); | |
| 81 EXPECT_FALSE(state.ParseSTSHeader(now, "max-age=3488923 includesubdomain=")); | |
| 82 EXPECT_FALSE(state.ParseSTSHeader( | |
| 83 now, "max-age=3488923 includesubdomain=true")); | |
| 84 EXPECT_FALSE(state.ParseSTSHeader(now, "max-age=3488923 includesubdomainsx")); | |
| 85 EXPECT_FALSE(state.ParseSTSHeader( | |
| 86 now, "max-age=3488923 includesubdomains x")); | |
| 87 EXPECT_FALSE(state.ParseSTSHeader(now, "max-age=34889.23 includesubdomains")); | |
| 88 EXPECT_FALSE(state.ParseSTSHeader(now, "max-age=34889 includesubdomains")); | |
| 89 | |
| 90 // Check that |state| was not updated by expecting the default | |
| 91 // values for its predictable fields. | |
| 92 EXPECT_EQ(state.upgrade_mode, | |
| 93 TransportSecurityState::DomainState::MODE_FORCE_HTTPS); | |
| 94 EXPECT_FALSE(state.include_subdomains); | |
| 95 } | |
| 96 | |
| 97 static bool GetPublicKeyHash(const net::X509Certificate::OSCertHandle& cert, | |
| 98 HashValue* hash) { | |
| 99 std::string der_bytes; | |
| 100 if (!net::X509Certificate::GetDEREncoded(cert, &der_bytes)) | |
| 101 return false; | |
| 102 | |
| 103 base::StringPiece spki; | |
| 104 if (!asn1::ExtractSPKIFromDERCert(der_bytes, &spki)) | |
| 105 return false; | |
| 106 | |
| 107 switch (hash->tag) { | |
| 108 case HASH_VALUE_SHA1: | |
| 109 base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(spki.data()), | |
| 110 spki.size(), hash->data()); | |
| 111 break; | |
| 112 case HASH_VALUE_SHA256: | |
| 113 crypto::SHA256HashString(spki, hash->data(), crypto::kSHA256Length); | |
| 114 break; | |
| 115 default: | |
| 116 NOTREACHED() << "Unknown HashValueTag " << hash->tag; | |
| 117 } | |
| 118 | |
| 119 return true; | |
| 120 } | |
| 121 | |
| 122 static std::string GetPinFromCert(X509Certificate* cert, HashValueTag tag) { | |
| 123 HashValue spki_hash(tag); | |
| 124 EXPECT_TRUE(GetPublicKeyHash(cert->os_cert_handle(), &spki_hash)); | |
| 125 | |
| 126 std::string base64; | |
| 127 base::Base64Encode(base::StringPiece( | |
| 128 reinterpret_cast<char*>(spki_hash.data()), spki_hash.size()), &base64); | |
| 129 | |
| 130 std::string label; | |
| 131 switch (tag) { | |
| 132 case HASH_VALUE_SHA1: | |
| 133 label = "pin-sha1="; | |
| 134 break; | |
| 135 case HASH_VALUE_SHA256: | |
| 136 label = "pin-sha256="; | |
| 137 break; | |
| 138 default: | |
| 139 NOTREACHED() << "Unknown HashValueTag " << tag; | |
| 140 } | |
| 141 | |
| 142 return label + HttpUtil::Quote(base64); | |
| 143 } | |
| 144 | |
| 145 static void TestBogusPinsHeaders(HashValueTag tag) { | |
| 146 TransportSecurityState::DomainState state; | |
| 147 SSLInfo ssl_info; | |
| 148 ssl_info.cert = | |
| 149 ImportCertFromFile(GetTestCertsDirectory(), "test_mail_google_com.pem"); | |
| 150 std::string good_pin = GetPinFromCert(ssl_info.cert, tag); | |
| 151 base::Time now = base::Time::Now(); | |
| 152 | |
| 153 // The backup pin is fake --- it just has to not be in the chain. | |
| 154 std::string backup_pin = "pin-sha1=" + | |
| 155 HttpUtil::Quote("6dcfXufJLW3J6S/9rRe4vUlBj5g="); | |
| 156 | |
| 157 EXPECT_FALSE(state.ParsePinsHeader(now, "", ssl_info)); | |
| 158 EXPECT_FALSE(state.ParsePinsHeader(now, " ", ssl_info)); | |
| 159 EXPECT_FALSE(state.ParsePinsHeader(now, "abc", ssl_info)); | |
| 160 EXPECT_FALSE(state.ParsePinsHeader(now, " abc", ssl_info)); | |
| 161 EXPECT_FALSE(state.ParsePinsHeader(now, " abc ", ssl_info)); | |
| 162 EXPECT_FALSE(state.ParsePinsHeader(now, "max-age", ssl_info)); | |
| 163 EXPECT_FALSE(state.ParsePinsHeader(now, " max-age", ssl_info)); | |
| 164 EXPECT_FALSE(state.ParsePinsHeader(now, " max-age ", ssl_info)); | |
| 165 EXPECT_FALSE(state.ParsePinsHeader(now, "max-age=", ssl_info)); | |
| 166 EXPECT_FALSE(state.ParsePinsHeader(now, " max-age=", ssl_info)); | |
| 167 EXPECT_FALSE(state.ParsePinsHeader(now, " max-age =", ssl_info)); | |
| 168 EXPECT_FALSE(state.ParsePinsHeader(now, " max-age= ", ssl_info)); | |
| 169 EXPECT_FALSE(state.ParsePinsHeader(now, " max-age = ", ssl_info)); | |
| 170 EXPECT_FALSE(state.ParsePinsHeader(now, " max-age = xy", ssl_info)); | |
| 171 EXPECT_FALSE(state.ParsePinsHeader( | |
| 172 now, | |
| 173 " max-age = 3488a923", | |
| 174 ssl_info)); | |
| 175 EXPECT_FALSE(state.ParsePinsHeader(now, "max-age=3488a923 ", ssl_info)); | |
| 176 EXPECT_FALSE(state.ParsePinsHeader(now, | |
| 177 "max-ag=3488923pins=" + good_pin + "," + backup_pin, | |
| 178 ssl_info)); | |
| 179 EXPECT_FALSE(state.ParsePinsHeader(now, "max-aged=3488923" + backup_pin, | |
| 180 ssl_info)); | |
| 181 EXPECT_FALSE(state.ParsePinsHeader(now, "max-aged=3488923; " + backup_pin, | |
| 182 ssl_info)); | |
| 183 EXPECT_FALSE(state.ParsePinsHeader(now, | |
| 184 "max-aged=3488923; " + backup_pin + ";" + backup_pin, | |
| 185 ssl_info)); | |
| 186 EXPECT_FALSE(state.ParsePinsHeader(now, | |
| 187 "max-aged=3488923; " + good_pin + ";" + good_pin, | |
| 188 ssl_info)); | |
| 189 EXPECT_FALSE(state.ParsePinsHeader(now, "max-aged=3488923; " + good_pin, | |
| 190 ssl_info)); | |
| 191 EXPECT_FALSE(state.ParsePinsHeader(now, "max-age==3488923", ssl_info)); | |
| 192 EXPECT_FALSE(state.ParsePinsHeader(now, "amax-age=3488923", ssl_info)); | |
| 193 EXPECT_FALSE(state.ParsePinsHeader(now, "max-age=-3488923", ssl_info)); | |
| 194 EXPECT_FALSE(state.ParsePinsHeader(now, "max-age=3488923;", ssl_info)); | |
| 195 EXPECT_FALSE(state.ParsePinsHeader(now, "max-age=3488923 e", ssl_info)); | |
| 196 EXPECT_FALSE(state.ParsePinsHeader( | |
| 197 now, | |
| 198 "max-age=3488923 includesubdomain", | |
| 199 ssl_info)); | |
| 200 EXPECT_FALSE(state.ParsePinsHeader(now, "max-age=34889.23", ssl_info)); | |
| 201 | |
| 202 // Check that |state| was not updated by expecting the default | |
| 203 // values for its predictable fields. | |
| 204 EXPECT_EQ(state.upgrade_mode, | |
| 205 TransportSecurityState::DomainState::MODE_FORCE_HTTPS); | |
| 206 EXPECT_FALSE(state.include_subdomains); | |
| 207 } | |
| 208 | |
| 209 TEST_F(TransportSecurityStateTest, BogusPinsHeadersSHA1) { | |
| 210 TestBogusPinsHeaders(HASH_VALUE_SHA1); | |
| 211 } | |
| 212 | |
| 213 TEST_F(TransportSecurityStateTest, BogusPinsHeadersSHA256) { | |
| 214 TestBogusPinsHeaders(HASH_VALUE_SHA256); | |
| 215 } | |
| 216 | |
| 217 TEST_F(TransportSecurityStateTest, ValidSTSHeaders) { | |
| 218 TransportSecurityState::DomainState state; | |
| 219 base::Time expiry; | |
| 220 base::Time now = base::Time::Now(); | |
| 221 | |
| 222 EXPECT_TRUE(state.ParseSTSHeader(now, "max-age=243")); | |
| 223 expiry = now + base::TimeDelta::FromSeconds(243); | |
| 224 EXPECT_EQ(expiry, state.upgrade_expiry); | |
| 225 EXPECT_FALSE(state.include_subdomains); | |
| 226 | |
| 227 EXPECT_TRUE(state.ParseSTSHeader(now, " Max-agE = 567")); | |
| 228 expiry = now + base::TimeDelta::FromSeconds(567); | |
| 229 EXPECT_EQ(expiry, state.upgrade_expiry); | |
| 230 EXPECT_FALSE(state.include_subdomains); | |
| 231 | |
| 232 EXPECT_TRUE(state.ParseSTSHeader(now, " mAx-aGe = 890 ")); | |
| 233 expiry = now + base::TimeDelta::FromSeconds(890); | |
| 234 EXPECT_EQ(expiry, state.upgrade_expiry); | |
| 235 EXPECT_FALSE(state.include_subdomains); | |
| 236 | |
| 237 EXPECT_TRUE(state.ParseSTSHeader(now, "max-age=123;incLudesUbdOmains")); | |
| 238 expiry = now + base::TimeDelta::FromSeconds(123); | |
| 239 EXPECT_EQ(expiry, state.upgrade_expiry); | |
| 240 EXPECT_TRUE(state.include_subdomains); | |
| 241 | |
| 242 EXPECT_TRUE(state.ParseSTSHeader(now, "incLudesUbdOmains; max-age=123")); | |
| 243 expiry = now + base::TimeDelta::FromSeconds(123); | |
| 244 EXPECT_EQ(expiry, state.upgrade_expiry); | |
| 245 EXPECT_TRUE(state.include_subdomains); | |
| 246 | |
| 247 EXPECT_TRUE(state.ParseSTSHeader(now, " incLudesUbdOmains; max-age=123")); | |
| 248 expiry = now + base::TimeDelta::FromSeconds(123); | |
| 249 EXPECT_EQ(expiry, state.upgrade_expiry); | |
| 250 EXPECT_TRUE(state.include_subdomains); | |
| 251 | |
| 252 EXPECT_TRUE(state.ParseSTSHeader(now, | |
| 253 " incLudesUbdOmains; max-age=123; pumpkin=kitten")); | |
| 254 expiry = now + base::TimeDelta::FromSeconds(123); | |
| 255 EXPECT_EQ(expiry, state.upgrade_expiry); | |
| 256 EXPECT_TRUE(state.include_subdomains); | |
| 257 | |
| 258 EXPECT_TRUE(state.ParseSTSHeader(now, | |
| 259 " pumpkin=894; incLudesUbdOmains; max-age=123 ")); | |
| 260 expiry = now + base::TimeDelta::FromSeconds(123); | |
| 261 EXPECT_EQ(expiry, state.upgrade_expiry); | |
| 262 EXPECT_TRUE(state.include_subdomains); | |
| 263 | |
| 264 EXPECT_TRUE(state.ParseSTSHeader(now, | |
| 265 " pumpkin; incLudesUbdOmains; max-age=123 ")); | |
| 266 expiry = now + base::TimeDelta::FromSeconds(123); | |
| 267 EXPECT_EQ(expiry, state.upgrade_expiry); | |
| 268 EXPECT_TRUE(state.include_subdomains); | |
| 269 | |
| 270 EXPECT_TRUE(state.ParseSTSHeader(now, | |
| 271 " pumpkin; incLudesUbdOmains; max-age=\"123\" ")); | |
| 272 expiry = now + base::TimeDelta::FromSeconds(123); | |
| 273 EXPECT_EQ(expiry, state.upgrade_expiry); | |
| 274 EXPECT_TRUE(state.include_subdomains); | |
| 275 | |
| 276 EXPECT_TRUE(state.ParseSTSHeader(now, | |
| 277 "animal=\"squirrel; distinguished\"; incLudesUbdOmains; max-age=123")); | |
| 278 expiry = now + base::TimeDelta::FromSeconds(123); | |
| 279 EXPECT_EQ(expiry, state.upgrade_expiry); | |
| 280 EXPECT_TRUE(state.include_subdomains); | |
| 281 | |
| 282 EXPECT_TRUE(state.ParseSTSHeader(now, "max-age=394082; incLudesUbdOmains")); | |
| 283 expiry = now + base::TimeDelta::FromSeconds(394082); | |
| 284 EXPECT_EQ(expiry, state.upgrade_expiry); | |
| 285 EXPECT_TRUE(state.include_subdomains); | |
| 286 | |
| 287 EXPECT_TRUE(state.ParseSTSHeader( | |
| 288 now, "max-age=39408299 ;incLudesUbdOmains")); | |
| 289 expiry = now + base::TimeDelta::FromSeconds( | |
| 290 std::min(TransportSecurityState::kMaxHSTSAgeSecs, 39408299l)); | |
| 291 EXPECT_EQ(expiry, state.upgrade_expiry); | |
| 292 EXPECT_TRUE(state.include_subdomains); | |
| 293 | |
| 294 EXPECT_TRUE(state.ParseSTSHeader( | |
| 295 now, "max-age=394082038 ; incLudesUbdOmains")); | |
| 296 expiry = now + base::TimeDelta::FromSeconds( | |
| 297 std::min(TransportSecurityState::kMaxHSTSAgeSecs, 394082038l)); | |
| 298 EXPECT_EQ(expiry, state.upgrade_expiry); | |
| 299 EXPECT_TRUE(state.include_subdomains); | |
| 300 | |
| 301 EXPECT_TRUE(state.ParseSTSHeader( | |
| 302 now, " max-age=0 ; incLudesUbdOmains ")); | |
| 303 expiry = now + base::TimeDelta::FromSeconds(0); | |
| 304 EXPECT_EQ(expiry, state.upgrade_expiry); | |
| 305 EXPECT_TRUE(state.include_subdomains); | |
| 306 // When max-age == 0, we downgrade to MODE_DEFAULT rather than deleting | |
| 307 // the entire DomainState. (That is because we currently overload | |
| 308 // DomainState to also include pins, and we don't want to invalidate any | |
| 309 // opportunistic pins that may be in place.) | |
| 310 EXPECT_EQ(TransportSecurityState::DomainState::MODE_DEFAULT, | |
| 311 state.upgrade_mode); | |
| 312 | |
| 313 EXPECT_TRUE(state.ParseSTSHeader( | |
| 314 now, | |
| 315 " max-age=999999999999999999999999999999999999999999999 ;" | |
| 316 " incLudesUbdOmains ")); | |
| 317 expiry = now + base::TimeDelta::FromSeconds( | |
| 318 TransportSecurityState::kMaxHSTSAgeSecs); | |
| 319 EXPECT_EQ(expiry, state.upgrade_expiry); | |
| 320 EXPECT_TRUE(state.include_subdomains); | |
| 321 } | |
| 322 | |
| 323 static void TestValidPinsHeaders(HashValueTag tag) { | |
| 324 TransportSecurityState::DomainState state; | |
| 325 base::Time expiry; | |
| 326 base::Time now = base::Time::Now(); | |
| 327 | |
| 328 // Set up a realistic SSLInfo with a realistic cert chain. | |
| 329 FilePath certs_dir = GetTestCertsDirectory(); | |
| 330 scoped_refptr<X509Certificate> ee_cert = | |
| 331 ImportCertFromFile(certs_dir, "2048-rsa-ee-by-2048-rsa-intermediate.pem"); | |
| 332 ASSERT_NE(static_cast<X509Certificate*>(NULL), ee_cert); | |
| 333 scoped_refptr<X509Certificate> intermediate = | |
| 334 ImportCertFromFile(certs_dir, "2048-rsa-intermediate.pem"); | |
| 335 ASSERT_NE(static_cast<X509Certificate*>(NULL), intermediate); | |
| 336 X509Certificate::OSCertHandles intermediates; | |
| 337 intermediates.push_back(intermediate->os_cert_handle()); | |
| 338 SSLInfo ssl_info; | |
| 339 ssl_info.cert = X509Certificate::CreateFromHandle(ee_cert->os_cert_handle(), | |
| 340 intermediates); | |
| 341 | |
| 342 // Add the root that signed the intermediate for this test. | |
| 343 scoped_refptr<X509Certificate> root_cert = | |
| 344 ImportCertFromFile(certs_dir, "2048-rsa-root.pem"); | |
| 345 ASSERT_NE(static_cast<X509Certificate*>(NULL), root_cert); | |
| 346 ScopedTestRoot scoped_root(root_cert); | |
| 347 | |
| 348 // Verify has the side-effect of populating public_key_hashes, which | |
| 349 // ParsePinsHeader needs. (It wants to check pins against the validated | |
| 350 // chain, not just the presented chain.) | |
| 351 int rv = ERR_FAILED; | |
| 352 CertVerifyResult result; | |
| 353 scoped_ptr<CertVerifier> verifier(CertVerifier::CreateDefault()); | |
| 354 TestCompletionCallback callback; | |
| 355 CertVerifier::RequestHandle handle = NULL; | |
| 356 rv = verifier->Verify(ssl_info.cert, "127.0.0.1", 0, NULL, &result, | |
| 357 callback.callback(), &handle, BoundNetLog()); | |
| 358 rv = callback.GetResult(rv); | |
| 359 ASSERT_EQ(OK, rv); | |
| 360 // Normally, ssl_client_socket_nss would do this, but for a unit test we | |
| 361 // fake it. | |
| 362 ssl_info.public_key_hashes = result.public_key_hashes; | |
| 363 std::string good_pin = GetPinFromCert(ssl_info.cert, /*tag*/HASH_VALUE_SHA1); | |
| 364 DLOG(WARNING) << "good pin: " << good_pin; | |
| 365 | |
| 366 // The backup pin is fake --- we just need an SPKI hash that does not match | |
| 367 // the hash of any SPKI in the certificate chain. | |
| 368 std::string backup_pin = "pin-sha1=" + | |
| 369 HttpUtil::Quote("6dcfXufJLW3J6S/9rRe4vUlBj5g="); | |
| 370 | |
| 371 EXPECT_TRUE(state.ParsePinsHeader( | |
| 372 now, | |
| 373 "max-age=243; " + good_pin + ";" + backup_pin, | |
| 374 ssl_info)); | |
| 375 expiry = now + base::TimeDelta::FromSeconds(243); | |
| 376 EXPECT_EQ(expiry, state.dynamic_spki_hashes_expiry); | |
| 377 | |
| 378 EXPECT_TRUE(state.ParsePinsHeader( | |
| 379 now, | |
| 380 " " + good_pin + "; " + backup_pin + " ; Max-agE = 567", | |
| 381 ssl_info)); | |
| 382 expiry = now + base::TimeDelta::FromSeconds(567); | |
| 383 EXPECT_EQ(expiry, state.dynamic_spki_hashes_expiry); | |
| 384 | |
| 385 EXPECT_TRUE(state.ParsePinsHeader( | |
| 386 now, | |
| 387 good_pin + ";" + backup_pin + " ; mAx-aGe = 890 ", | |
| 388 ssl_info)); | |
| 389 expiry = now + base::TimeDelta::FromSeconds(890); | |
| 390 EXPECT_EQ(expiry, state.dynamic_spki_hashes_expiry); | |
| 391 | |
| 392 EXPECT_TRUE(state.ParsePinsHeader( | |
| 393 now, | |
| 394 good_pin + ";" + backup_pin + "; max-age=123;IGNORED;", | |
| 395 ssl_info)); | |
| 396 expiry = now + base::TimeDelta::FromSeconds(123); | |
| 397 EXPECT_EQ(expiry, state.dynamic_spki_hashes_expiry); | |
| 398 | |
| 399 EXPECT_TRUE(state.ParsePinsHeader( | |
| 400 now, | |
| 401 "max-age=394082;" + backup_pin + ";" + good_pin + "; ", | |
| 402 ssl_info)); | |
| 403 expiry = now + base::TimeDelta::FromSeconds(394082); | |
| 404 EXPECT_EQ(expiry, state.dynamic_spki_hashes_expiry); | |
| 405 | |
| 406 EXPECT_TRUE(state.ParsePinsHeader( | |
| 407 now, | |
| 408 "max-age=39408299 ;" + backup_pin + ";" + good_pin + "; ", | |
| 409 ssl_info)); | |
| 410 expiry = now + base::TimeDelta::FromSeconds( | |
| 411 std::min(TransportSecurityState::kMaxHSTSAgeSecs, 39408299l)); | |
| 412 EXPECT_EQ(expiry, state.dynamic_spki_hashes_expiry); | |
| 413 | |
| 414 EXPECT_TRUE(state.ParsePinsHeader( | |
| 415 now, | |
| 416 "max-age=39408038 ; cybers=39408038 ; " + | |
| 417 good_pin + ";" + backup_pin + "; ", | |
| 418 ssl_info)); | |
| 419 expiry = now + base::TimeDelta::FromSeconds( | |
| 420 std::min(TransportSecurityState::kMaxHSTSAgeSecs, 394082038l)); | |
| 421 EXPECT_EQ(expiry, state.dynamic_spki_hashes_expiry); | |
| 422 | |
| 423 EXPECT_TRUE(state.ParsePinsHeader( | |
| 424 now, | |
| 425 " max-age=0 ; " + good_pin + ";" + backup_pin, | |
| 426 ssl_info)); | |
| 427 expiry = now + base::TimeDelta::FromSeconds(0); | |
| 428 EXPECT_EQ(expiry, state.dynamic_spki_hashes_expiry); | |
| 429 | |
| 430 EXPECT_TRUE(state.ParsePinsHeader( | |
| 431 now, | |
| 432 " max-age=999999999999999999999999999999999999999999999 ; " + | |
| 433 backup_pin + ";" + good_pin + "; ", | |
| 434 ssl_info)); | |
| 435 expiry = now + | |
| 436 base::TimeDelta::FromSeconds(TransportSecurityState::kMaxHSTSAgeSecs); | |
| 437 EXPECT_EQ(expiry, state.dynamic_spki_hashes_expiry); | |
| 438 } | |
| 439 | |
| 440 TEST_F(TransportSecurityStateTest, ValidPinsHeadersSHA1) { | |
| 441 TestValidPinsHeaders(HASH_VALUE_SHA1); | |
| 442 } | |
| 443 | |
| 444 TEST_F(TransportSecurityStateTest, ValidPinsHeadersSHA256) { | |
| 445 TestValidPinsHeaders(HASH_VALUE_SHA256); | |
| 446 } | |
| 447 | |
| 448 TEST_F(TransportSecurityStateTest, SimpleMatches) { | 49 TEST_F(TransportSecurityStateTest, SimpleMatches) { |
| 449 TransportSecurityState state; | 50 TransportSecurityState state; |
| 450 TransportSecurityState::DomainState domain_state; | 51 TransportSecurityState::DomainState domain_state; |
| 451 const base::Time current_time(base::Time::Now()); | 52 const base::Time current_time(base::Time::Now()); |
| 452 const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); | 53 const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000); |
| 453 | 54 |
| 454 EXPECT_FALSE(state.GetDomainState("yahoo.com", true, &domain_state)); | 55 EXPECT_FALSE(state.GetDomainState("yahoo.com", true, &domain_state)); |
| 455 domain_state.upgrade_expiry = expiry; | 56 domain_state.upgrade_expiry = expiry; |
| 456 state.EnableHost("yahoo.com", domain_state); | 57 state.EnableHost("yahoo.com", domain_state); |
| 457 EXPECT_TRUE(state.GetDomainState("yahoo.com", true, &domain_state)); | 58 EXPECT_TRUE(state.GetDomainState("yahoo.com", true, &domain_state)); |
| (...skipping 455 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 913 EXPECT_TRUE(HasPins("dev.twitter.com")); | 514 EXPECT_TRUE(HasPins("dev.twitter.com")); |
| 914 EXPECT_TRUE(HasPins("business.twitter.com")); | 515 EXPECT_TRUE(HasPins("business.twitter.com")); |
| 915 EXPECT_TRUE(HasPins("platform.twitter.com")); | 516 EXPECT_TRUE(HasPins("platform.twitter.com")); |
| 916 EXPECT_TRUE(HasPins("si0.twimg.com")); | 517 EXPECT_TRUE(HasPins("si0.twimg.com")); |
| 917 EXPECT_TRUE(HasPins("twimg0-a.akamaihd.net")); | 518 EXPECT_TRUE(HasPins("twimg0-a.akamaihd.net")); |
| 918 } | 519 } |
| 919 | 520 |
| 920 static bool AddHash(const std::string& type_and_base64, | 521 static bool AddHash(const std::string& type_and_base64, |
| 921 HashValueVector* out) { | 522 HashValueVector* out) { |
| 922 HashValue hash; | 523 HashValue hash; |
| 923 | 524 if (!hash.FromString(type_and_base64)) |
| 924 if (!TransportSecurityState::ParsePin(type_and_base64, &hash)) | |
| 925 return false; | 525 return false; |
| 926 | 526 |
| 927 out->push_back(hash); | 527 out->push_back(hash); |
| 928 return true; | 528 return true; |
| 929 } | 529 } |
| 930 | 530 |
| 931 TEST_F(TransportSecurityStateTest, PinValidationWithRejectedCerts) { | 531 TEST_F(TransportSecurityStateTest, PinValidationWithRejectedCerts) { |
| 932 // kGoodPath is plus.google.com via Google Internet Authority. | 532 // kGoodPath is plus.google.com via Google Internet Authority. |
| 933 static const char* kGoodPath[] = { | 533 static const char* kGoodPath[] = { |
| 934 "sha1/4BjDjn8v2lWeUFQnqSs0BgbIcrU=", | 534 "sha1/4BjDjn8v2lWeUFQnqSs0BgbIcrU=", |
| (...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1227 // Expect to fail for SNI hosts when not searching the SNI list: | 827 // Expect to fail for SNI hosts when not searching the SNI list: |
| 1228 EXPECT_FALSE(TransportSecurityState::IsGooglePinnedProperty( | 828 EXPECT_FALSE(TransportSecurityState::IsGooglePinnedProperty( |
| 1229 "gmail.com", false)); | 829 "gmail.com", false)); |
| 1230 EXPECT_FALSE(TransportSecurityState::IsGooglePinnedProperty( | 830 EXPECT_FALSE(TransportSecurityState::IsGooglePinnedProperty( |
| 1231 "googlegroups.com", false)); | 831 "googlegroups.com", false)); |
| 1232 EXPECT_FALSE(TransportSecurityState::IsGooglePinnedProperty( | 832 EXPECT_FALSE(TransportSecurityState::IsGooglePinnedProperty( |
| 1233 "www.googlegroups.com", false)); | 833 "www.googlegroups.com", false)); |
| 1234 } | 834 } |
| 1235 | 835 |
| 1236 } // namespace net | 836 } // namespace net |
| OLD | NEW |