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

Unified Diff: net/http/transport_security_state.cc

Issue 1212613004: Build and send HPKP violation reports (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: remove unnecessary net::'s 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 side-by-side diff with in-line comments
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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/http/transport_security_state.cc
diff --git a/net/http/transport_security_state.cc b/net/http/transport_security_state.cc
index 8ad73581e85a2670ac48fcd5c43e3f7dd2161ba3..44f96b15c71e92062b29bb68ae1949ceb912defa 100644
--- a/net/http/transport_security_state.cc
+++ b/net/http/transport_security_state.cc
@@ -19,6 +19,7 @@
#include "base/base64.h"
#include "base/build_time.h"
+#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/metrics/histogram_macros.h"
@@ -26,11 +27,13 @@
#include "base/sha1.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "base/values.h"
#include "crypto/sha2.h"
#include "net/base/dns_util.h"
+#include "net/base/host_port_pair.h"
#include "net/cert/x509_cert_types.h"
#include "net/cert/x509_certificate.h"
#include "net/http/http_security_headers.h"
@@ -47,6 +50,91 @@ namespace {
#include "net/http/transport_security_state_static.h"
+std::string TimeToISO8601(const base::Time& t) {
+ base::Time::Exploded exploded;
+ t.UTCExplode(&exploded);
+ return base::StringPrintf(
+ "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", exploded.year, exploded.month,
+ exploded.day_of_month, exploded.hour, exploded.minute, exploded.second,
+ exploded.millisecond);
+}
+
+scoped_ptr<base::ListValue> GetPEMEncodedChainAsList(
+ const net::X509Certificate* cert_chain) {
+ if (!cert_chain)
+ return make_scoped_ptr(new base::ListValue());
+
+ scoped_ptr<base::ListValue> result(new base::ListValue());
+ std::vector<std::string> pem_encoded_chain;
+ cert_chain->GetPEMEncodedChain(&pem_encoded_chain);
+ for (const std::string& cert : pem_encoded_chain)
+ result->Append(make_scoped_ptr(new base::StringValue(cert)));
+
+ return result.Pass();
+}
+
+bool GetHPKPReport(const HostPortPair& host_port_pair,
+ const TransportSecurityState::PKPState& pkp_state,
+ const X509Certificate* served_certificate_chain,
+ const X509Certificate* validated_certificate_chain,
+ std::string* serialized_report) {
+ // TODO(estark): keep track of reports already sent and rate-limit,
+ // break loops
+ if (pkp_state.report_uri.is_empty())
+ return false;
+
+ base::DictionaryValue report;
+ base::Time now = base::Time::Now();
+ report.SetString("date-time", TimeToISO8601(now));
+ report.SetString("hostname", host_port_pair.host());
+ report.SetInteger("port", host_port_pair.port());
+ report.SetString("effective-expiration-date",
+ TimeToISO8601(pkp_state.expiry));
+ report.SetBoolean("include-subdomains", pkp_state.include_subdomains);
+ report.SetString("noted-hostname", pkp_state.domain);
+
+ scoped_ptr<base::ListValue> served_certificate_chain_list =
+ GetPEMEncodedChainAsList(served_certificate_chain);
+ scoped_ptr<base::ListValue> validated_certificate_chain_list =
+ GetPEMEncodedChainAsList(validated_certificate_chain);
+ report.Set("served-certificate-chain", served_certificate_chain_list.Pass());
+ report.Set("validated-certificate-chain",
+ validated_certificate_chain_list.Pass());
+
+ scoped_ptr<base::ListValue> known_pin_list(new base::ListValue());
+ for (const auto& hash_value : pkp_state.spki_hashes) {
+ std::string known_pin;
+
+ switch (hash_value.tag) {
+ case HASH_VALUE_SHA1:
+ known_pin += "pin-sha1=";
+ break;
+ case HASH_VALUE_SHA256:
+ known_pin += "pin-sha256=";
+ break;
+ }
+
+ std::string base64_value;
+ base::Base64Encode(
+ base::StringPiece(reinterpret_cast<const char*>(hash_value.data()),
+ hash_value.size()),
+ &base64_value);
+ known_pin += "\"" + base64_value + "\"";
+
+ known_pin_list->Append(
+ scoped_ptr<base::Value>(new base::StringValue(known_pin)));
+ }
+
+ report.Set("known-pins", known_pin_list.Pass());
+
+ if (!base::JSONWriter::Write(report, serialized_report)) {
+ LOG(ERROR) << "Failed to serialize HPKP violation report.";
+ return false;
+ }
+
+ return true;
+}
+
std::string HashesToBase64String(const HashValueVector& hashes) {
std::string str;
for (size_t i = 0; i != hashes.size(); ++i) {
@@ -510,24 +598,28 @@ bool TransportSecurityState::ShouldUpgradeToSSL(const std::string& host) {
}
bool TransportSecurityState::CheckPublicKeyPins(
- const std::string& host,
+ const HostPortPair& host_port_pair,
bool is_issued_by_known_root,
const HashValueVector& public_key_hashes,
+ const X509Certificate* served_certificate_chain,
+ const X509Certificate* validated_certificate_chain,
+ const PublicKeyPinReportStatus report_status,
std::string* pinning_failure_log) {
// Perform pin validation if, and only if, all these conditions obtain:
//
// * the server's certificate chain chains up to a known root (i.e. not a
// user-installed trust anchor); and
// * the server actually has public key pins.
- if (!is_issued_by_known_root || !HasPublicKeyPins(host)) {
+ if (!is_issued_by_known_root || !HasPublicKeyPins(host_port_pair.host())) {
return true;
}
- bool pins_are_valid =
- CheckPublicKeyPinsImpl(host, public_key_hashes, pinning_failure_log);
+ bool pins_are_valid = CheckPublicKeyPinsImpl(
+ host_port_pair, public_key_hashes, served_certificate_chain,
+ validated_certificate_chain, report_status, pinning_failure_log);
if (!pins_are_valid) {
LOG(ERROR) << *pinning_failure_log;
- ReportUMAOnPinFailure(host);
+ ReportUMAOnPinFailure(host_port_pair.host());
}
UMA_HISTOGRAM_BOOLEAN("Net.PublicKeyPinSuccess", pins_are_valid);
@@ -555,6 +647,12 @@ void TransportSecurityState::SetDelegate(
delegate_ = delegate;
}
+void TransportSecurityState::SetReportSender(
+ TransportSecurityState::ReportSender* report_sender) {
+ DCHECK(CalledOnValidThread());
+ report_sender_ = report_sender;
+}
+
void TransportSecurityState::AddHSTSInternal(
const std::string& host,
TransportSecurityState::STSState::UpgradeMode upgrade_mode,
@@ -813,20 +911,41 @@ bool TransportSecurityState::IsBuildTimely() {
}
bool TransportSecurityState::CheckPublicKeyPinsImpl(
- const std::string& host,
+ const HostPortPair& host_port_pair,
const HashValueVector& hashes,
+ const X509Certificate* served_certificate_chain,
+ const X509Certificate* validated_certificate_chain,
+ const PublicKeyPinReportStatus report_status,
std::string* failure_log) {
- PKPState dynamic_state;
- if (GetDynamicPKPState(host, &dynamic_state))
- return dynamic_state.CheckPublicKeyPins(hashes, failure_log);
-
- PKPState static_pkp_state;
+ PKPState pkp_state;
STSState unused;
- if (GetStaticDomainState(host, &unused, &static_pkp_state))
- return static_pkp_state.CheckPublicKeyPins(hashes, failure_log);
- // HasPublicKeyPins should have returned true in order for this method
- // to have been called, so if we fall through to here, it's an error.
+ if (!GetDynamicPKPState(host_port_pair.host(), &pkp_state) &&
+ !GetStaticDomainState(host_port_pair.host(), &unused, &pkp_state)) {
+ // HasPublicKeyPins should have returned true in order for this method
+ // to have been called, so if we fall through to here, it's an error.
+ return false;
+ }
+
+ if (pkp_state.CheckPublicKeyPins(hashes, failure_log))
+ return true;
+
+ if (!report_sender_ || report_status != ENABLE_PIN_REPORTS ||
+ pkp_state.report_uri.is_empty()) {
+ return false;
+ }
+
+ DCHECK(pkp_state.report_uri.is_valid());
+
+ std::string serialized_report;
+
+ if (!GetHPKPReport(host_port_pair, pkp_state, served_certificate_chain,
+ validated_certificate_chain, &serialized_report)) {
+ return false;
+ }
+
+ report_sender_->Send(pkp_state.report_uri, serialized_report);
+
return false;
}
« 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