Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(518)

Side by Side Diff: net/http/transport_security_state.cc

Issue 1211933005: Initial (partial) implementation of HPKP violation reporting (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: style fixes, comments Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/http/transport_security_state.h ('k') | net/http/transport_security_state_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « net/http/transport_security_state.h ('k') | net/http/transport_security_state_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698