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 "net/http/transport_security_state.h" 6 7 #if defined(USE_OPENSSL) 8 #include <openssl/ecdsa.h> 9 #include <openssl/ssl.h> 10 #else // !defined(USE_OPENSSL) 11 #include <cryptohi.h> 12 #include <hasht.h> 13 #include <keyhi.h> 14 #include <nspr.h> 15 #include <pk11pub.h> 16 #endif 17 18 #include <algorithm> 19 20 #include "base/base64.h" 21 #include "base/build_time.h" 22 #include "base/logging.h" 23 #include "base/memory/scoped_ptr.h" 24 #include "base/metrics/histogram.h" 25 #include "base/sha1.h" 26 #include "base/strings/string_number_conversions.h" 27 #include "base/strings/string_util.h" 28 #include "base/strings/utf_string_conversions.h" 29 #include "base/time/time.h" 30 #include "base/values.h" 31 #include "crypto/sha2.h" 32 #include "net/base/dns_util.h" 33 #include "net/cert/x509_cert_types.h" 34 #include "net/cert/x509_certificate.h" 35 #include "net/http/http_security_headers.h" 36 #include "net/ssl/ssl_info.h" 37 #include "url/gurl.h" 38 39 #if defined(USE_OPENSSL) 40 #include "crypto/openssl_util.h" 41 #endif 42 43 namespace net { 44 45 namespace { 46 47 std::string HashesToBase64String(const HashValueVector& hashes) { 48 std::string str; 49 for (size_t i = 0; i != hashes.size(); ++i) { 50 if (i != 0) 51 str += ","; 52 str += hashes[i].ToString(); 53 } 54 return str; 55 } 56 57 std::string HashHost(const std::string& canonicalized_host) { 58 char hashed[crypto::kSHA256Length]; 59 crypto::SHA256HashString(canonicalized_host, hashed, sizeof(hashed)); 60 return std::string(hashed, sizeof(hashed)); 61 } 62 63 // Returns true if the intersection of |a| and |b| is not empty. If either 64 // |a| or |b| is empty, returns false. 65 bool HashesIntersect(const HashValueVector& a, 66 const HashValueVector& b) { 67 for (HashValueVector::const_iterator i = a.begin(); i != a.end(); ++i) { 68 HashValueVector::const_iterator j = 69 std::find_if(b.begin(), b.end(), HashValuesEqual(*i)); 70 if (j != b.end()) 71 return true; 72 } 73 return false; 74 } 75 76 bool AddHash(const char* sha1_hash, 77 HashValueVector* out) { 78 HashValue hash(HASH_VALUE_SHA1); 79 memcpy(hash.data(), sha1_hash, hash.size()); 80 out->push_back(hash); 81 return true; 82 } 83 84 } // namespace 85 86 TransportSecurityState::TransportSecurityState() 87 : delegate_(NULL) { 88 DCHECK(CalledOnValidThread()); 89 } 90 91 TransportSecurityState::Iterator::Iterator(const TransportSecurityState& state) 92 : iterator_(state.enabled_hosts_.begin()), 93 end_(state.enabled_hosts_.end()) { 94 } 95 96 TransportSecurityState::Iterator::~Iterator() {} 97 98 void TransportSecurityState::SetDelegate( 99 TransportSecurityState::Delegate* delegate) { 100 DCHECK(CalledOnValidThread()); 101 delegate_ = delegate; 102 } 103 104 void TransportSecurityState::EnableHost(const std::string& host, 105 const DomainState& state) { 106 DCHECK(CalledOnValidThread()); 107 108 const std::string canonicalized_host = CanonicalizeHost(host); 109 if (canonicalized_host.empty()) 110 return; 111 112 DomainState state_copy(state); 113 // No need to store this value since it is redundant. (|canonicalized_host| 114 // is the map key.) 115 state_copy.domain.clear(); 116 117 enabled_hosts_[HashHost(canonicalized_host)] = state_copy; 118 DirtyNotify(); 119 } 120 121 bool TransportSecurityState::DeleteDynamicDataForHost(const std::string& host) { 122 DCHECK(CalledOnValidThread()); 123 124 const std::string canonicalized_host = CanonicalizeHost(host); 125 if (canonicalized_host.empty()) 126 return false; 127 128 DomainStateMap::iterator i = enabled_hosts_.find( 129 HashHost(canonicalized_host)); 130 if (i != enabled_hosts_.end()) { 131 enabled_hosts_.erase(i); 132 DirtyNotify(); 133 return true; 134 } 135 return false; 136 } 137 138 bool TransportSecurityState::GetDomainState(const std::string& host, 139 bool sni_enabled, 140 DomainState* result) { 141 DCHECK(CalledOnValidThread()); 142 143 DomainState state; 144 const std::string canonicalized_host = CanonicalizeHost(host); 145 if (canonicalized_host.empty()) 146 return false; 147 148 bool has_preload = GetStaticDomainState(canonicalized_host, sni_enabled, 149 &state); 150 std::string canonicalized_preload = CanonicalizeHost(state.domain); 151 GetDynamicDomainState(host, &state); 152 153 base::Time current_time(base::Time::Now()); 154 155 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) { 156 std::string host_sub_chunk(&canonicalized_host[i], 157 canonicalized_host.size() - i); 158 // Exact match of a preload always wins. 159 if (has_preload && host_sub_chunk == canonicalized_preload) { 160 *result = state; 161 return true; 162 } 163 164 DomainStateMap::iterator j = 165 enabled_hosts_.find(HashHost(host_sub_chunk)); 166 if (j == enabled_hosts_.end()) 167 continue; 168 169 if (current_time > j->second.upgrade_expiry && 170 current_time > j->second.dynamic_spki_hashes_expiry) { 171 enabled_hosts_.erase(j); 172 DirtyNotify(); 173 continue; 174 } 175 176 state = j->second; 177 state.domain = DNSDomainToString(host_sub_chunk); 178 179 // Succeed if we matched the domain exactly or if subdomain matches are 180 // allowed. 181 if (i == 0 || j->second.sts_include_subdomains || 182 j->second.pkp_include_subdomains) { 183 *result = state; 184 return true; 185 } 186 187 return false; 188 } 189 190 return false; 191 } 192 193 void TransportSecurityState::ClearDynamicData() { 194 DCHECK(CalledOnValidThread()); 195 enabled_hosts_.clear(); 196 } 197 198 void TransportSecurityState::DeleteAllDynamicDataSince(const base::Time& time) { 199 DCHECK(CalledOnValidThread()); 200 201 bool dirtied = false; 202 203 DomainStateMap::iterator i = enabled_hosts_.begin(); 204 while (i != enabled_hosts_.end()) { 205 if (i->second.created >= time) { 206 dirtied = true; 207 enabled_hosts_.erase(i++); 208 } else { 209 i++; 210 } 211 } 212 213 if (dirtied) 214 DirtyNotify(); 215 } 216 217 TransportSecurityState::~TransportSecurityState() { 218 DCHECK(CalledOnValidThread()); 219 } 220 221 void TransportSecurityState::DirtyNotify() { 222 DCHECK(CalledOnValidThread()); 223 224 if (delegate_) 225 delegate_->StateIsDirty(this); 226 } 227 228 // static 229 std::string TransportSecurityState::CanonicalizeHost(const std::string& host) { 230 // We cannot perform the operations as detailed in the spec here as |host| 231 // has already undergone IDN processing before it reached us. Thus, we check 232 // that there are no invalid characters in the host and lowercase the result. 233 234 std::string new_host; 235 if (!DNSDomainFromDot(host, &new_host)) { 236 // DNSDomainFromDot can fail if any label is > 63 bytes or if the whole 237 // name is >255 bytes. However, search terms can have those properties. 238 return std::string(); 239 } 240 241 for (size_t i = 0; new_host[i]; i += new_host[i] + 1) { 242 const unsigned label_length = static_cast<unsigned>(new_host[i]); 243 if (!label_length) 244 break; 245 246 for (size_t j = 0; j < label_length; ++j) { 247 new_host[i + 1 + j] = tolower(new_host[i + 1 + j]); 248 } 249 } 250 251 return new_host; 252 } 253 254 // |ReportUMAOnPinFailure| uses these to report which domain was associated 255 // with the public key pinning failure. 256 // 257 // DO NOT CHANGE THE ORDERING OF THESE NAMES OR REMOVE ANY OF THEM. Add new 258 // domains at the END of the listing (but before DOMAIN_NUM_EVENTS). 259 enum SecondLevelDomainName { 260 DOMAIN_NOT_PINNED, 261 262 DOMAIN_GOOGLE_COM, 263 DOMAIN_ANDROID_COM, 264 DOMAIN_GOOGLE_ANALYTICS_COM, 265 DOMAIN_GOOGLEPLEX_COM, 266 DOMAIN_YTIMG_COM, 267 DOMAIN_GOOGLEUSERCONTENT_COM, 268 DOMAIN_YOUTUBE_COM, 269 DOMAIN_GOOGLEAPIS_COM, 270 DOMAIN_GOOGLEADSERVICES_COM, 271 DOMAIN_GOOGLECODE_COM, 272 DOMAIN_APPSPOT_COM, 273 DOMAIN_GOOGLESYNDICATION_COM, 274 DOMAIN_DOUBLECLICK_NET, 275 DOMAIN_GSTATIC_COM, 276 DOMAIN_GMAIL_COM, 277 DOMAIN_GOOGLEMAIL_COM, 278 DOMAIN_GOOGLEGROUPS_COM, 279 280 DOMAIN_TORPROJECT_ORG, 281 282 DOMAIN_TWITTER_COM, 283 DOMAIN_TWIMG_COM, 284 285 DOMAIN_AKAMAIHD_NET, 286 287 DOMAIN_TOR2WEB_ORG, 288 289 DOMAIN_YOUTU_BE, 290 DOMAIN_GOOGLECOMMERCE_COM, 291 DOMAIN_URCHIN_COM, 292 DOMAIN_GOO_GL, 293 DOMAIN_G_CO, 294 DOMAIN_GOOGLE_AC, 295 DOMAIN_GOOGLE_AD, 296 DOMAIN_GOOGLE_AE, 297 DOMAIN_GOOGLE_AF, 298 DOMAIN_GOOGLE_AG, 299 DOMAIN_GOOGLE_AM, 300 DOMAIN_GOOGLE_AS, 301 DOMAIN_GOOGLE_AT, 302 DOMAIN_GOOGLE_AZ, 303 DOMAIN_GOOGLE_BA, 304 DOMAIN_GOOGLE_BE, 305 DOMAIN_GOOGLE_BF, 306 DOMAIN_GOOGLE_BG, 307 DOMAIN_GOOGLE_BI, 308 DOMAIN_GOOGLE_BJ, 309 DOMAIN_GOOGLE_BS, 310 DOMAIN_GOOGLE_BY, 311 DOMAIN_GOOGLE_CA, 312 DOMAIN_GOOGLE_CAT, 313 DOMAIN_GOOGLE_CC, 314 DOMAIN_GOOGLE_CD, 315 DOMAIN_GOOGLE_CF, 316 DOMAIN_GOOGLE_CG, 317 DOMAIN_GOOGLE_CH, 318 DOMAIN_GOOGLE_CI, 319 DOMAIN_GOOGLE_CL, 320 DOMAIN_GOOGLE_CM, 321 DOMAIN_GOOGLE_CN, 322 DOMAIN_CO_AO, 323 DOMAIN_CO_BW, 324 DOMAIN_CO_CK, 325 DOMAIN_CO_CR, 326 DOMAIN_CO_HU, 327 DOMAIN_CO_ID, 328 DOMAIN_CO_IL, 329 DOMAIN_CO_IM, 330 DOMAIN_CO_IN, 331 DOMAIN_CO_JE, 332 DOMAIN_CO_JP, 333 DOMAIN_CO_KE, 334 DOMAIN_CO_KR, 335 DOMAIN_CO_LS, 336 DOMAIN_CO_MA, 337 DOMAIN_CO_MZ, 338 DOMAIN_CO_NZ, 339 DOMAIN_CO_TH, 340 DOMAIN_CO_TZ, 341 DOMAIN_CO_UG, 342 DOMAIN_CO_UK, 343 DOMAIN_CO_UZ, 344 DOMAIN_CO_VE, 345 DOMAIN_CO_VI, 346 DOMAIN_CO_ZA, 347 DOMAIN_CO_ZM, 348 DOMAIN_CO_ZW, 349 DOMAIN_COM_AF, 350 DOMAIN_COM_AG, 351 DOMAIN_COM_AI, 352 DOMAIN_COM_AR, 353 DOMAIN_COM_AU, 354 DOMAIN_COM_BD, 355 DOMAIN_COM_BH, 356 DOMAIN_COM_BN, 357 DOMAIN_COM_BO, 358 DOMAIN_COM_BR, 359 DOMAIN_COM_BY, 360 DOMAIN_COM_BZ, 361 DOMAIN_COM_CN, 362 DOMAIN_COM_CO, 363 DOMAIN_COM_CU, 364 DOMAIN_COM_CY, 365 DOMAIN_COM_DO, 366 DOMAIN_COM_EC, 367 DOMAIN_COM_EG, 368 DOMAIN_COM_ET, 369 DOMAIN_COM_FJ, 370 DOMAIN_COM_GE, 371 DOMAIN_COM_GH, 372 DOMAIN_COM_GI, 373 DOMAIN_COM_GR, 374 DOMAIN_COM_GT, 375 DOMAIN_COM_HK, 376 DOMAIN_COM_IQ, 377 DOMAIN_COM_JM, 378 DOMAIN_COM_JO, 379 DOMAIN_COM_KH, 380 DOMAIN_COM_KW, 381 DOMAIN_COM_LB, 382 DOMAIN_COM_LY, 383 DOMAIN_COM_MT, 384 DOMAIN_COM_MX, 385 DOMAIN_COM_MY, 386 DOMAIN_COM_NA, 387 DOMAIN_COM_NF, 388 DOMAIN_COM_NG, 389 DOMAIN_COM_NI, 390 DOMAIN_COM_NP, 391 DOMAIN_COM_NR, 392 DOMAIN_COM_OM, 393 DOMAIN_COM_PA, 394 DOMAIN_COM_PE, 395 DOMAIN_COM_PH, 396 DOMAIN_COM_PK, 397 DOMAIN_COM_PL, 398 DOMAIN_COM_PR, 399 DOMAIN_COM_PY, 400 DOMAIN_COM_QA, 401 DOMAIN_COM_RU, 402 DOMAIN_COM_SA, 403 DOMAIN_COM_SB, 404 DOMAIN_COM_SG, 405 DOMAIN_COM_SL, 406 DOMAIN_COM_SV, 407 DOMAIN_COM_TJ, 408 DOMAIN_COM_TN, 409 DOMAIN_COM_TR, 410 DOMAIN_COM_TW, 411 DOMAIN_COM_UA, 412 DOMAIN_COM_UY, 413 DOMAIN_COM_VC, 414 DOMAIN_COM_VE, 415 DOMAIN_COM_VN, 416 DOMAIN_GOOGLE_CV, 417 DOMAIN_GOOGLE_CZ, 418 DOMAIN_GOOGLE_DE, 419 DOMAIN_GOOGLE_DJ, 420 DOMAIN_GOOGLE_DK, 421 DOMAIN_GOOGLE_DM, 422 DOMAIN_GOOGLE_DZ, 423 DOMAIN_GOOGLE_EE, 424 DOMAIN_GOOGLE_ES, 425 DOMAIN_GOOGLE_FI, 426 DOMAIN_GOOGLE_FM, 427 DOMAIN_GOOGLE_FR, 428 DOMAIN_GOOGLE_GA, 429 DOMAIN_GOOGLE_GE, 430 DOMAIN_GOOGLE_GG, 431 DOMAIN_GOOGLE_GL, 432 DOMAIN_GOOGLE_GM, 433 DOMAIN_GOOGLE_GP, 434 DOMAIN_GOOGLE_GR, 435 DOMAIN_GOOGLE_GY, 436 DOMAIN_GOOGLE_HK, 437 DOMAIN_GOOGLE_HN, 438 DOMAIN_GOOGLE_HR, 439 DOMAIN_GOOGLE_HT, 440 DOMAIN_GOOGLE_HU, 441 DOMAIN_GOOGLE_IE, 442 DOMAIN_GOOGLE_IM, 443 DOMAIN_GOOGLE_INFO, 444 DOMAIN_GOOGLE_IQ, 445 DOMAIN_GOOGLE_IS, 446 DOMAIN_GOOGLE_IT, 447 DOMAIN_IT_AO, 448 DOMAIN_GOOGLE_JE, 449 DOMAIN_GOOGLE_JO, 450 DOMAIN_GOOGLE_JOBS, 451 DOMAIN_GOOGLE_JP, 452 DOMAIN_GOOGLE_KG, 453 DOMAIN_GOOGLE_KI, 454 DOMAIN_GOOGLE_KZ, 455 DOMAIN_GOOGLE_LA, 456 DOMAIN_GOOGLE_LI, 457 DOMAIN_GOOGLE_LK, 458 DOMAIN_GOOGLE_LT, 459 DOMAIN_GOOGLE_LU, 460 DOMAIN_GOOGLE_LV, 461 DOMAIN_GOOGLE_MD, 462 DOMAIN_GOOGLE_ME, 463 DOMAIN_GOOGLE_MG, 464 DOMAIN_GOOGLE_MK, 465 DOMAIN_GOOGLE_ML, 466 DOMAIN_GOOGLE_MN, 467 DOMAIN_GOOGLE_MS, 468 DOMAIN_GOOGLE_MU, 469 DOMAIN_GOOGLE_MV, 470 DOMAIN_GOOGLE_MW, 471 DOMAIN_GOOGLE_NE, 472 DOMAIN_NE_JP, 473 DOMAIN_GOOGLE_NET, 474 DOMAIN_GOOGLE_NL, 475 DOMAIN_GOOGLE_NO, 476 DOMAIN_GOOGLE_NR, 477 DOMAIN_GOOGLE_NU, 478 DOMAIN_OFF_AI, 479 DOMAIN_GOOGLE_PK, 480 DOMAIN_GOOGLE_PL, 481 DOMAIN_GOOGLE_PN, 482 DOMAIN_GOOGLE_PS, 483 DOMAIN_GOOGLE_PT, 484 DOMAIN_GOOGLE_RO, 485 DOMAIN_GOOGLE_RS, 486 DOMAIN_GOOGLE_RU, 487 DOMAIN_GOOGLE_RW, 488 DOMAIN_GOOGLE_SC, 489 DOMAIN_GOOGLE_SE, 490 DOMAIN_GOOGLE_SH, 491 DOMAIN_GOOGLE_SI, 492 DOMAIN_GOOGLE_SK, 493 DOMAIN_GOOGLE_SM, 494 DOMAIN_GOOGLE_SN, 495 DOMAIN_GOOGLE_SO, 496 DOMAIN_GOOGLE_ST, 497 DOMAIN_GOOGLE_TD, 498 DOMAIN_GOOGLE_TG, 499 DOMAIN_GOOGLE_TK, 500 DOMAIN_GOOGLE_TL, 501 DOMAIN_GOOGLE_TM, 502 DOMAIN_GOOGLE_TN, 503 DOMAIN_GOOGLE_TO, 504 DOMAIN_GOOGLE_TP, 505 DOMAIN_GOOGLE_TT, 506 DOMAIN_GOOGLE_US, 507 DOMAIN_GOOGLE_UZ, 508 DOMAIN_GOOGLE_VG, 509 DOMAIN_GOOGLE_VU, 510 DOMAIN_GOOGLE_WS, 511 512 DOMAIN_CHROMIUM_ORG, 513 514 DOMAIN_CRYPTO_CAT, 515 DOMAIN_LAVABIT_COM, 516 517 DOMAIN_GOOGLETAGMANAGER_COM, 518 519 // Boundary value for UMA_HISTOGRAM_ENUMERATION: 520 DOMAIN_NUM_EVENTS 521 }; 522 523 // PublicKeyPins contains a number of SubjectPublicKeyInfo hashes for a site. 524 // The validated certificate chain for the site must not include any of 525 // |excluded_hashes| and must include one or more of |required_hashes|. 526 struct PublicKeyPins { 527 const char* const* required_hashes; 528 const char* const* excluded_hashes; 529 }; 530 531 struct HSTSPreload { 532 uint8 length; 533 bool include_subdomains; 534 char dns_name[38]; 535 bool https_required; 536 PublicKeyPins pins; 537 SecondLevelDomainName second_level_domain_name; 538 }; 539 540 static bool HasPreload(const struct HSTSPreload* entries, size_t num_entries, 541 const std::string& canonicalized_host, size_t i, 542 TransportSecurityState::DomainState* out, bool* ret) { 543 for (size_t j = 0; j < num_entries; j++) { 544 if (entries[j].length == canonicalized_host.size() - i && 545 memcmp(entries[j].dns_name, &canonicalized_host[i], 546 entries[j].length) == 0) { 547 if (!entries[j].include_subdomains && i != 0) { 548 *ret = false; 549 } else { 550 out->sts_include_subdomains = entries[j].include_subdomains; 551 out->pkp_include_subdomains = entries[j].include_subdomains; 552 *ret = true; 553 if (!entries[j].https_required) 554 out->upgrade_mode = TransportSecurityState::DomainState::MODE_DEFAULT; 555 if (entries[j].pins.required_hashes) { 556 const char* const* sha1_hash = entries[j].pins.required_hashes; 557 while (*sha1_hash) { 558 AddHash(*sha1_hash, &out->static_spki_hashes); 559 sha1_hash++; 560 } 561 } 562 if (entries[j].pins.excluded_hashes) { 563 const char* const* sha1_hash = entries[j].pins.excluded_hashes; 564 while (*sha1_hash) { 565 AddHash(*sha1_hash, &out->bad_static_spki_hashes); 566 sha1_hash++; 567 } 568 } 569 } 570 return true; 571 } 572 } 573 return false; 574 } 575 576 #include "net/http/transport_security_state_static.h" 577 578 // Returns the HSTSPreload entry for the |canonicalized_host| in |entries|, 579 // or NULL if there is none. Prefers exact hostname matches to those that 580 // match only because HSTSPreload.include_subdomains is true. 581 // 582 // |canonicalized_host| should be the hostname as canonicalized by 583 // CanonicalizeHost. 584 static const struct HSTSPreload* GetHSTSPreload( 585 const std::string& canonicalized_host, 586 const struct HSTSPreload* entries, 587 size_t num_entries) { 588 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) { 589 for (size_t j = 0; j < num_entries; j++) { 590 const struct HSTSPreload* entry = entries + j; 591 592 if (i != 0 && !entry->include_subdomains) 593 continue; 594 595 if (entry->length == canonicalized_host.size() - i && 596 memcmp(entry->dns_name, &canonicalized_host[i], entry->length) == 0) { 597 return entry; 598 } 599 } 600 } 601 602 return NULL; 603 } 604 605 bool TransportSecurityState::AddHSTSHeader(const std::string& host, 606 const std::string& value) { 607 DCHECK(CalledOnValidThread()); 608 609 base::Time now = base::Time::Now(); 610 base::TimeDelta max_age; 611 TransportSecurityState::DomainState domain_state; 612 GetDynamicDomainState(host, &domain_state); 613 if (ParseHSTSHeader(value, &max_age, &domain_state.sts_include_subdomains)) { 614 // Handle max-age == 0 615 if (max_age.InSeconds() == 0) 616 domain_state.upgrade_mode = DomainState::MODE_DEFAULT; 617 else 618 domain_state.upgrade_mode = DomainState::MODE_FORCE_HTTPS; 619 domain_state.created = now; 620 domain_state.upgrade_expiry = now + max_age; 621 EnableHost(host, domain_state); 622 return true; 623 } 624 return false; 625 } 626 627 bool TransportSecurityState::AddHPKPHeader(const std::string& host, 628 const std::string& value, 629 const SSLInfo& ssl_info) { 630 DCHECK(CalledOnValidThread()); 631 632 base::Time now = base::Time::Now(); 633 base::TimeDelta max_age; 634 TransportSecurityState::DomainState domain_state; 635 GetDynamicDomainState(host, &domain_state); 636 if (ParseHPKPHeader(value, ssl_info.public_key_hashes, 637 &max_age, &domain_state.pkp_include_subdomains, 638 &domain_state.dynamic_spki_hashes)) { 639 // TODO(palmer): http://crbug.com/243865 handle max-age == 0. 640 domain_state.created = now; 641 domain_state.dynamic_spki_hashes_expiry = now + max_age; 642 EnableHost(host, domain_state); 643 return true; 644 } 645 return false; 646 } 647 648 bool TransportSecurityState::AddHSTS(const std::string& host, 649 const base::Time& expiry, 650 bool include_subdomains) { 651 DCHECK(CalledOnValidThread()); 652 653 // Copy-and-modify the existing DomainState for this host (if any). 654 TransportSecurityState::DomainState domain_state; 655 const std::string canonicalized_host = CanonicalizeHost(host); 656 const std::string hashed_host = HashHost(canonicalized_host); 657 DomainStateMap::const_iterator i = enabled_hosts_.find( 658 hashed_host); 659 if (i != enabled_hosts_.end()) 660 domain_state = i->second; 661 662 domain_state.created = base::Time::Now(); 663 domain_state.sts_include_subdomains = include_subdomains; 664 domain_state.upgrade_expiry = expiry; 665 domain_state.upgrade_mode = DomainState::MODE_FORCE_HTTPS; 666 EnableHost(host, domain_state); 667 return true; 668 } 669 670 bool TransportSecurityState::AddHPKP(const std::string& host, 671 const base::Time& expiry, 672 bool include_subdomains, 673 const HashValueVector& hashes) { 674 DCHECK(CalledOnValidThread()); 675 676 // Copy-and-modify the existing DomainState for this host (if any). 677 TransportSecurityState::DomainState domain_state; 678 const std::string canonicalized_host = CanonicalizeHost(host); 679 const std::string hashed_host = HashHost(canonicalized_host); 680 DomainStateMap::const_iterator i = enabled_hosts_.find( 681 hashed_host); 682 if (i != enabled_hosts_.end()) 683 domain_state = i->second; 684 685 domain_state.created = base::Time::Now(); 686 domain_state.pkp_include_subdomains = include_subdomains; 687 domain_state.dynamic_spki_hashes_expiry = expiry; 688 domain_state.dynamic_spki_hashes = hashes; 689 EnableHost(host, domain_state); 690 return true; 691 } 692 693 // static 694 bool TransportSecurityState::IsGooglePinnedProperty(const std::string& host, 695 bool sni_enabled) { 696 std::string canonicalized_host = CanonicalizeHost(host); 697 const struct HSTSPreload* entry = 698 GetHSTSPreload(canonicalized_host, kPreloadedSTS, kNumPreloadedSTS); 699 700 if (entry && entry->pins.required_hashes == kGoogleAcceptableCerts) 701 return true; 702 703 if (sni_enabled) { 704 entry = GetHSTSPreload(canonicalized_host, kPreloadedSNISTS, 705 kNumPreloadedSNISTS); 706 if (entry && entry->pins.required_hashes == kGoogleAcceptableCerts) 707 return true; 708 } 709 710 return false; 711 } 712 713 // static 714 void TransportSecurityState::ReportUMAOnPinFailure(const std::string& host) { 715 std::string canonicalized_host = CanonicalizeHost(host); 716 717 const struct HSTSPreload* entry = 718 GetHSTSPreload(canonicalized_host, kPreloadedSTS, kNumPreloadedSTS); 719 720 if (!entry) { 721 entry = GetHSTSPreload(canonicalized_host, kPreloadedSNISTS, 722 kNumPreloadedSNISTS); 723 } 724 725 if (!entry) { 726 // We don't care to report pin failures for dynamic pins. 727 return; 728 } 729 730 DCHECK(entry); 731 DCHECK(entry->pins.required_hashes); 732 DCHECK(entry->second_level_domain_name != DOMAIN_NOT_PINNED); 733 734 UMA_HISTOGRAM_ENUMERATION("Net.PublicKeyPinFailureDomain", 735 entry->second_level_domain_name, DOMAIN_NUM_EVENTS); 736 } 737 738 // static 739 bool TransportSecurityState::IsBuildTimely() { 740 const base::Time build_time = base::GetBuildTime(); 741 // We consider built-in information to be timely for 10 weeks. 742 return (base::Time::Now() - build_time).InDays() < 70 /* 10 weeks */; 743 } 744 745 bool TransportSecurityState::GetStaticDomainState( 746 const std::string& canonicalized_host, 747 bool sni_enabled, 748 DomainState* out) { 749 DCHECK(CalledOnValidThread()); 750 751 out->upgrade_mode = DomainState::MODE_FORCE_HTTPS; 752 out->sts_include_subdomains = false; 753 out->pkp_include_subdomains = false; 754 755 const bool is_build_timely = IsBuildTimely(); 756 757 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) { 758 std::string host_sub_chunk(&canonicalized_host[i], 759 canonicalized_host.size() - i); 760 out->domain = DNSDomainToString(host_sub_chunk); 761 bool ret; 762 if (is_build_timely && 763 HasPreload(kPreloadedSTS, kNumPreloadedSTS, canonicalized_host, i, out, 764 &ret)) { 765 return ret; 766 } 767 if (sni_enabled && 768 is_build_timely && 769 HasPreload(kPreloadedSNISTS, kNumPreloadedSNISTS, canonicalized_host, i, 770 out, &ret)) { 771 return ret; 772 } 773 } 774 775 return false; 776 } 777 778 bool TransportSecurityState::GetDynamicDomainState(const std::string& host, 779 DomainState* result) { 780 DCHECK(CalledOnValidThread()); 781 782 DomainState state; 783 const std::string canonicalized_host = CanonicalizeHost(host); 784 if (canonicalized_host.empty()) 785 return false; 786 787 base::Time current_time(base::Time::Now()); 788 789 for (size_t i = 0; canonicalized_host[i]; i += canonicalized_host[i] + 1) { 790 std::string host_sub_chunk(&canonicalized_host[i], 791 canonicalized_host.size() - i); 792 DomainStateMap::iterator j = 793 enabled_hosts_.find(HashHost(host_sub_chunk)); 794 if (j == enabled_hosts_.end()) 795 continue; 796 797 if (current_time > j->second.upgrade_expiry && 798 current_time > j->second.dynamic_spki_hashes_expiry) { 799 enabled_hosts_.erase(j); 800 DirtyNotify(); 801 continue; 802 } 803 804 state = j->second; 805 state.domain = DNSDomainToString(host_sub_chunk); 806 807 // Succeed if we matched the domain exactly or if subdomain matches are 808 // allowed. 809 if (i == 0 || j->second.sts_include_subdomains || 810 j->second.pkp_include_subdomains) { 811 *result = state; 812 return true; 813 } 814 815 return false; 816 } 817 818 return false; 819 } 820 821 822 void TransportSecurityState::AddOrUpdateEnabledHosts( 823 const std::string& hashed_host, const DomainState& state) { 824 DCHECK(CalledOnValidThread()); 825 enabled_hosts_[hashed_host] = state; 826 } 827 828 TransportSecurityState::DomainState::DomainState() 829 : upgrade_mode(MODE_DEFAULT), 830 created(base::Time::Now()), 831 sts_include_subdomains(false), 832 pkp_include_subdomains(false) { 833 } 834 835 TransportSecurityState::DomainState::~DomainState() { 836 } 837 838 bool TransportSecurityState::DomainState::CheckPublicKeyPins( 839 const HashValueVector& hashes) const { 840 // Validate that hashes is not empty. By the time this code is called (in 841 // production), that should never happen, but it's good to be defensive. 842 // And, hashes *can* be empty in some test scenarios. 843 if (hashes.empty()) { 844 LOG(ERROR) << "Rejecting empty public key chain for public-key-pinned " 845 "domain " << domain; 846 return false; 847 } 848 849 if (HashesIntersect(bad_static_spki_hashes, hashes)) { 850 LOG(ERROR) << "Rejecting public key chain for domain " << domain 851 << ". Validated chain: " << HashesToBase64String(hashes) 852 << ", matches one or more bad hashes: " 853 << HashesToBase64String(bad_static_spki_hashes); 854 return false; 855 } 856 857 // If there are no pins, then any valid chain is acceptable. 858 if (dynamic_spki_hashes.empty() && static_spki_hashes.empty()) 859 return true; 860 861 if (HashesIntersect(dynamic_spki_hashes, hashes) || 862 HashesIntersect(static_spki_hashes, hashes)) { 863 return true; 864 } 865 866 LOG(ERROR) << "Rejecting public key chain for domain " << domain 867 << ". Validated chain: " << HashesToBase64String(hashes) 868 << ", expected: " << HashesToBase64String(dynamic_spki_hashes) 869 << " or: " << HashesToBase64String(static_spki_hashes); 870 return false; 871 } 872 873 bool TransportSecurityState::DomainState::ShouldUpgradeToSSL() const { 874 return upgrade_mode == MODE_FORCE_HTTPS; 875 } 876 877 bool TransportSecurityState::DomainState::ShouldSSLErrorsBeFatal() const { 878 return true; 879 } 880 881 bool TransportSecurityState::DomainState::HasPublicKeyPins() const { 882 return static_spki_hashes.size() > 0 || 883 bad_static_spki_hashes.size() > 0 || 884 dynamic_spki_hashes.size() > 0; 885 } 886 887 } // namespace 888