| 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/http/transport_security_state.h" | 5 #include "net/http/transport_security_state.h" |
| 6 | 6 |
| 7 #if defined(USE_OPENSSL) | 7 #if defined(USE_OPENSSL) |
| 8 #include <openssl/ecdsa.h> | 8 #include <openssl/ecdsa.h> |
| 9 #include <openssl/ssl.h> | 9 #include <openssl/ssl.h> |
| 10 #else // !defined(USE_OPENSSL) | 10 #else // !defined(USE_OPENSSL) |
| (...skipping 501 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 512 return true; | 512 return true; |
| 513 } | 513 } |
| 514 | 514 |
| 515 return false; | 515 return false; |
| 516 } | 516 } |
| 517 | 517 |
| 518 bool TransportSecurityState::CheckPublicKeyPins( | 518 bool TransportSecurityState::CheckPublicKeyPins( |
| 519 const std::string& host, | 519 const std::string& host, |
| 520 bool is_issued_by_known_root, | 520 bool is_issued_by_known_root, |
| 521 const HashValueVector& public_key_hashes, | 521 const HashValueVector& public_key_hashes, |
| 522 uint16_t port, |
| 523 const scoped_refptr<X509Certificate>& served_certificate_chain, |
| 524 const scoped_refptr<X509Certificate>& validated_certificate_chain, |
| 525 const PublicKeyPinReportStatus report_status, |
| 522 std::string* pinning_failure_log) { | 526 std::string* pinning_failure_log) { |
| 523 // Perform pin validation if, and only if, all these conditions obtain: | 527 // Perform pin validation if, and only if, all these conditions obtain: |
| 524 // | 528 // |
| 525 // * the server's certificate chain chains up to a known root (i.e. not a | 529 // * the server's certificate chain chains up to a known root (i.e. not a |
| 526 // user-installed trust anchor); and | 530 // user-installed trust anchor); and |
| 527 // * the server actually has public key pins. | 531 // * the server actually has public key pins. |
| 528 if (!is_issued_by_known_root || !HasPublicKeyPins(host)) { | 532 if (!is_issued_by_known_root || !HasPublicKeyPins(host)) { |
| 529 return true; | 533 return true; |
| 530 } | 534 } |
| 531 | 535 |
| 532 bool pins_are_valid = | 536 bool pins_are_valid = CheckPublicKeyPinsImpl( |
| 533 CheckPublicKeyPinsImpl(host, public_key_hashes, pinning_failure_log); | 537 host, public_key_hashes, port, served_certificate_chain, |
| 538 validated_certificate_chain, report_status, pinning_failure_log); |
| 534 if (!pins_are_valid) { | 539 if (!pins_are_valid) { |
| 535 LOG(ERROR) << *pinning_failure_log; | 540 LOG(ERROR) << *pinning_failure_log; |
| 536 ReportUMAOnPinFailure(host); | 541 ReportUMAOnPinFailure(host); |
| 537 } | 542 } |
| 538 | 543 |
| 539 UMA_HISTOGRAM_BOOLEAN("Net.PublicKeyPinSuccess", pins_are_valid); | 544 UMA_HISTOGRAM_BOOLEAN("Net.PublicKeyPinSuccess", pins_are_valid); |
| 540 return pins_are_valid; | 545 return pins_are_valid; |
| 541 } | 546 } |
| 542 | 547 |
| 543 bool TransportSecurityState::HasPublicKeyPins(const std::string& host) { | 548 bool TransportSecurityState::HasPublicKeyPins(const std::string& host) { |
| 544 DomainState dynamic_state; | 549 DomainState dynamic_state; |
| 545 if (GetDynamicDomainState(host, &dynamic_state)) | 550 if (GetDynamicDomainState(host, &dynamic_state)) |
| 546 return dynamic_state.HasPublicKeyPins(); | 551 return dynamic_state.HasPublicKeyPins(); |
| 547 | 552 |
| 548 DomainState static_state; | 553 DomainState static_state; |
| 549 if (GetStaticDomainState(host, &static_state)) { | 554 if (GetStaticDomainState(host, &static_state)) { |
| 550 if (static_state.HasPublicKeyPins()) | 555 if (static_state.HasPublicKeyPins()) |
| 551 return true; | 556 return true; |
| 552 } | 557 } |
| 553 | 558 |
| 554 return false; | 559 return false; |
| 555 } | 560 } |
| 556 | 561 |
| 557 void TransportSecurityState::SetDelegate( | 562 void TransportSecurityState::SetDelegate( |
| 558 TransportSecurityState::Delegate* delegate) { | 563 TransportSecurityState::Delegate* delegate) { |
| 559 DCHECK(CalledOnValidThread()); | 564 DCHECK(CalledOnValidThread()); |
| 560 delegate_ = delegate; | 565 delegate_ = delegate; |
| 561 } | 566 } |
| 562 | 567 |
| 568 void TransportSecurityState::SetReporter( |
| 569 TransportSecurityState::Reporter* reporter) { |
| 570 DCHECK(CalledOnValidThread()); |
| 571 reporter_ = reporter; |
| 572 } |
| 573 |
| 563 void TransportSecurityState::AddHSTSInternal( | 574 void TransportSecurityState::AddHSTSInternal( |
| 564 const std::string& host, | 575 const std::string& host, |
| 565 TransportSecurityState::DomainState::UpgradeMode upgrade_mode, | 576 TransportSecurityState::DomainState::UpgradeMode upgrade_mode, |
| 566 const base::Time& expiry, | 577 const base::Time& expiry, |
| 567 bool include_subdomains) { | 578 bool include_subdomains) { |
| 568 DCHECK(CalledOnValidThread()); | 579 DCHECK(CalledOnValidThread()); |
| 569 | 580 |
| 570 // Copy-and-modify the existing DomainState for this host (if any). | 581 // Copy-and-modify the existing DomainState for this host (if any). |
| 571 DomainState domain_state; | 582 DomainState domain_state; |
| 572 const std::string canonicalized_host = CanonicalizeHost(host); | 583 const std::string canonicalized_host = CanonicalizeHost(host); |
| 573 const std::string hashed_host = HashHost(canonicalized_host); | 584 const std::string hashed_host = HashHost(canonicalized_host); |
| 574 DomainStateMap::const_iterator i = enabled_hosts_.find(hashed_host); | 585 DomainStateMap::const_iterator i = enabled_hosts_.find(hashed_host); |
| 575 if (i != enabled_hosts_.end()) | 586 if (i != enabled_hosts_.end()) |
| 576 domain_state = i->second; | 587 domain_state = i->second; |
| 577 | 588 |
| 578 domain_state.sts.last_observed = base::Time::Now(); | 589 domain_state.sts.last_observed = base::Time::Now(); |
| 579 domain_state.sts.include_subdomains = include_subdomains; | 590 domain_state.sts.include_subdomains = include_subdomains; |
| 580 domain_state.sts.expiry = expiry; | 591 domain_state.sts.expiry = expiry; |
| 581 domain_state.sts.upgrade_mode = upgrade_mode; | 592 domain_state.sts.upgrade_mode = upgrade_mode; |
| 582 EnableHost(host, domain_state); | 593 EnableHost(host, domain_state); |
| 583 } | 594 } |
| 584 | 595 |
| 585 void TransportSecurityState::AddHPKPInternal(const std::string& host, | 596 void TransportSecurityState::AddHPKPInternal(const std::string& host, |
| 586 const base::Time& last_observed, | 597 const base::Time& last_observed, |
| 587 const base::Time& expiry, | 598 const base::Time& expiry, |
| 588 bool include_subdomains, | 599 bool include_subdomains, |
| 589 const HashValueVector& hashes) { | 600 const HashValueVector& hashes, |
| 601 const std::string& report_uri) { |
| 590 DCHECK(CalledOnValidThread()); | 602 DCHECK(CalledOnValidThread()); |
| 591 | 603 |
| 592 // Copy-and-modify the existing DomainState for this host (if any). | 604 // Copy-and-modify the existing DomainState for this host (if any). |
| 593 DomainState domain_state; | 605 DomainState domain_state; |
| 594 const std::string canonicalized_host = CanonicalizeHost(host); | 606 const std::string canonicalized_host = CanonicalizeHost(host); |
| 595 const std::string hashed_host = HashHost(canonicalized_host); | 607 const std::string hashed_host = HashHost(canonicalized_host); |
| 596 DomainStateMap::const_iterator i = enabled_hosts_.find(hashed_host); | 608 DomainStateMap::const_iterator i = enabled_hosts_.find(hashed_host); |
| 597 if (i != enabled_hosts_.end()) | 609 if (i != enabled_hosts_.end()) |
| 598 domain_state = i->second; | 610 domain_state = i->second; |
| 599 | 611 |
| 600 domain_state.pkp.last_observed = last_observed; | 612 domain_state.pkp.last_observed = last_observed; |
| 601 domain_state.pkp.expiry = expiry; | 613 domain_state.pkp.expiry = expiry; |
| 602 domain_state.pkp.include_subdomains = include_subdomains; | 614 domain_state.pkp.include_subdomains = include_subdomains; |
| 603 domain_state.pkp.spki_hashes = hashes; | 615 domain_state.pkp.spki_hashes = hashes; |
| 616 domain_state.pkp.report_uri = report_uri; |
| 604 EnableHost(host, domain_state); | 617 EnableHost(host, domain_state); |
| 605 } | 618 } |
| 606 | 619 |
| 607 void TransportSecurityState::EnableHost(const std::string& host, | 620 void TransportSecurityState::EnableHost(const std::string& host, |
| 608 const DomainState& state) { | 621 const DomainState& state) { |
| 609 DCHECK(CalledOnValidThread()); | 622 DCHECK(CalledOnValidThread()); |
| 610 | 623 |
| 611 const std::string canonicalized_host = CanonicalizeHost(host); | 624 const std::string canonicalized_host = CanonicalizeHost(host); |
| 612 if (canonicalized_host.empty()) | 625 if (canonicalized_host.empty()) |
| 613 return; | 626 return; |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 711 | 724 |
| 712 bool TransportSecurityState::AddHPKPHeader(const std::string& host, | 725 bool TransportSecurityState::AddHPKPHeader(const std::string& host, |
| 713 const std::string& value, | 726 const std::string& value, |
| 714 const SSLInfo& ssl_info) { | 727 const SSLInfo& ssl_info) { |
| 715 DCHECK(CalledOnValidThread()); | 728 DCHECK(CalledOnValidThread()); |
| 716 | 729 |
| 717 base::Time now = base::Time::Now(); | 730 base::Time now = base::Time::Now(); |
| 718 base::TimeDelta max_age; | 731 base::TimeDelta max_age; |
| 719 bool include_subdomains; | 732 bool include_subdomains; |
| 720 HashValueVector spki_hashes; | 733 HashValueVector spki_hashes; |
| 734 std::string report_uri; |
| 735 |
| 721 if (!ParseHPKPHeader(value, ssl_info.public_key_hashes, &max_age, | 736 if (!ParseHPKPHeader(value, ssl_info.public_key_hashes, &max_age, |
| 722 &include_subdomains, &spki_hashes)) { | 737 &include_subdomains, &spki_hashes, &report_uri)) { |
| 723 return false; | 738 return false; |
| 724 } | 739 } |
| 725 // Handle max-age == 0. | 740 // Handle max-age == 0. |
| 726 if (max_age.InSeconds() == 0) | 741 if (max_age.InSeconds() == 0) |
| 727 spki_hashes.clear(); | 742 spki_hashes.clear(); |
| 728 AddHPKPInternal(host, now, now + max_age, include_subdomains, spki_hashes); | 743 AddHPKPInternal(host, now, now + max_age, include_subdomains, spki_hashes, |
| 744 report_uri); |
| 729 return true; | 745 return true; |
| 730 } | 746 } |
| 731 | 747 |
| 732 void TransportSecurityState::AddHSTS(const std::string& host, | 748 void TransportSecurityState::AddHSTS(const std::string& host, |
| 733 const base::Time& expiry, | 749 const base::Time& expiry, |
| 734 bool include_subdomains) { | 750 bool include_subdomains) { |
| 735 DCHECK(CalledOnValidThread()); | 751 DCHECK(CalledOnValidThread()); |
| 736 AddHSTSInternal(host, DomainState::MODE_FORCE_HTTPS, expiry, | 752 AddHSTSInternal(host, DomainState::MODE_FORCE_HTTPS, expiry, |
| 737 include_subdomains); | 753 include_subdomains); |
| 738 } | 754 } |
| 739 | 755 |
| 740 void TransportSecurityState::AddHPKP(const std::string& host, | 756 void TransportSecurityState::AddHPKP(const std::string& host, |
| 741 const base::Time& expiry, | 757 const base::Time& expiry, |
| 742 bool include_subdomains, | 758 bool include_subdomains, |
| 743 const HashValueVector& hashes) { | 759 const HashValueVector& hashes, |
| 760 const std::string& report_uri) { |
| 744 DCHECK(CalledOnValidThread()); | 761 DCHECK(CalledOnValidThread()); |
| 745 AddHPKPInternal(host, base::Time::Now(), expiry, include_subdomains, hashes); | 762 AddHPKPInternal(host, base::Time::Now(), expiry, include_subdomains, hashes, |
| 763 report_uri); |
| 746 } | 764 } |
| 747 | 765 |
| 748 // static | 766 // static |
| 749 bool TransportSecurityState::IsGooglePinnedProperty(const std::string& host) { | 767 bool TransportSecurityState::IsGooglePinnedProperty(const std::string& host) { |
| 750 PreloadResult result; | 768 PreloadResult result; |
| 751 return DecodeHSTSPreload(host, &result) && result.has_pins && | 769 return DecodeHSTSPreload(host, &result) && result.has_pins && |
| 752 kPinsets[result.pinset_id].accepted_pins == kGoogleAcceptableCerts; | 770 kPinsets[result.pinset_id].accepted_pins == kGoogleAcceptableCerts; |
| 753 } | 771 } |
| 754 | 772 |
| 755 // static | 773 // static |
| (...skipping 22 matching lines...) Expand all Loading... |
| 778 #else | 796 #else |
| 779 const base::Time build_time = base::GetBuildTime(); | 797 const base::Time build_time = base::GetBuildTime(); |
| 780 // We consider built-in information to be timely for 10 weeks. | 798 // We consider built-in information to be timely for 10 weeks. |
| 781 return (base::Time::Now() - build_time).InDays() < 70 /* 10 weeks */; | 799 return (base::Time::Now() - build_time).InDays() < 70 /* 10 weeks */; |
| 782 #endif | 800 #endif |
| 783 } | 801 } |
| 784 | 802 |
| 785 bool TransportSecurityState::CheckPublicKeyPinsImpl( | 803 bool TransportSecurityState::CheckPublicKeyPinsImpl( |
| 786 const std::string& host, | 804 const std::string& host, |
| 787 const HashValueVector& hashes, | 805 const HashValueVector& hashes, |
| 806 uint16_t port, |
| 807 const scoped_refptr<X509Certificate>& served_certificate_chain, |
| 808 const scoped_refptr<X509Certificate>& validated_certificate_chain, |
| 809 const PublicKeyPinReportStatus report_status, |
| 788 std::string* failure_log) { | 810 std::string* failure_log) { |
| 789 DomainState dynamic_state; | 811 DomainState dynamic_state; |
| 790 if (GetDynamicDomainState(host, &dynamic_state)) | 812 if (GetDynamicDomainState(host, &dynamic_state)) { |
| 791 return dynamic_state.CheckPublicKeyPins(hashes, failure_log); | 813 bool result = dynamic_state.CheckPublicKeyPins(hashes, failure_log); |
| 814 |
| 815 if (result || !reporter_ || |
| 816 report_status == DO_NOT_SEND_PUBLIC_KEY_PIN_REPORT) |
| 817 return result; |
| 818 |
| 819 GURL report_uri; |
| 820 std::string serialized_report; |
| 821 |
| 822 if (!reporter_->GetHPKPReportUri(dynamic_state.pkp, &report_uri)) |
| 823 return result; |
| 824 |
| 825 if (!reporter_->BuildHPKPReport( |
| 826 host, port, dynamic_state.pkp.expiry, |
| 827 dynamic_state.pkp.include_subdomains, dynamic_state.pkp.domain, |
| 828 served_certificate_chain, validated_certificate_chain, |
| 829 dynamic_state.pkp.spki_hashes, &serialized_report)) { |
| 830 LOG(ERROR) << "Failed to build HPKP report"; |
| 831 return result; |
| 832 } |
| 833 |
| 834 reporter_->SendHPKPReport(report_uri, serialized_report); |
| 835 } |
| 792 | 836 |
| 793 DomainState static_state; | 837 DomainState static_state; |
| 794 if (GetStaticDomainState(host, &static_state)) | 838 if (GetStaticDomainState(host, &static_state)) |
| 795 return static_state.CheckPublicKeyPins(hashes, failure_log); | 839 return static_state.CheckPublicKeyPins(hashes, failure_log); |
| 796 | 840 |
| 797 // HasPublicKeyPins should have returned true in order for this method | 841 // HasPublicKeyPins should have returned true in order for this method |
| 798 // to have been called, so if we fall through to here, it's an error. | 842 // to have been called, so if we fall through to here, it's an error. |
| 799 return false; | 843 return false; |
| 800 } | 844 } |
| 801 | 845 |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 993 TransportSecurityState::DomainState::STSState::~STSState() { | 1037 TransportSecurityState::DomainState::STSState::~STSState() { |
| 994 } | 1038 } |
| 995 | 1039 |
| 996 TransportSecurityState::DomainState::PKPState::PKPState() { | 1040 TransportSecurityState::DomainState::PKPState::PKPState() { |
| 997 } | 1041 } |
| 998 | 1042 |
| 999 TransportSecurityState::DomainState::PKPState::~PKPState() { | 1043 TransportSecurityState::DomainState::PKPState::~PKPState() { |
| 1000 } | 1044 } |
| 1001 | 1045 |
| 1002 } // namespace | 1046 } // namespace |
| OLD | NEW |