Skip to content

Commit

Permalink
Merge pull request #13062 from /issues/18830
Browse files Browse the repository at this point in the history
Add partitioned HSTS storage support.
  • Loading branch information
goodov authored May 26, 2022
2 parents 3933e62 + 2d6ed5b commit 1100f7b
Show file tree
Hide file tree
Showing 19 changed files with 1,660 additions and 23 deletions.
659 changes: 659 additions & 0 deletions browser/ephemeral_storage/hsts_partitioning_browsertest.cc

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions chromium_src/net/base/features.cc
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,9 @@ const base::Feature kBraveFirstPartyEphemeralStorage{
const base::Feature kBravePartitionBlobStorage{
"BravePartitionBlobStorage", base::FEATURE_ENABLED_BY_DEFAULT};

// Partition HSTS state storage by top frame site.
const base::Feature kBravePartitionHSTS{"BravePartitionHSTS",
base::FEATURE_ENABLED_BY_DEFAULT};

} // namespace features
} // namespace net
1 change: 1 addition & 0 deletions chromium_src/net/base/features.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ NET_EXPORT extern const base::FeatureParam<int>
kBraveEphemeralStorageKeepAliveTimeInSeconds;
NET_EXPORT extern const base::Feature kBraveFirstPartyEphemeralStorage;
NET_EXPORT extern const base::Feature kBravePartitionBlobStorage;
NET_EXPORT extern const base::Feature kBravePartitionHSTS;

} // namespace features
} // namespace net
Expand Down
17 changes: 17 additions & 0 deletions chromium_src/net/base/schemeful_site.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/* Copyright (c) 2022 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef BRAVE_CHROMIUM_SRC_NET_BASE_SCHEMEFUL_SITE_H_
#define BRAVE_CHROMIUM_SRC_NET_BASE_SCHEMEFUL_SITE_H_

#define NetworkIsolationKey \
NetworkIsolationKey; \
friend class HSTSPartitionHashHelper

#include "src/net/base/schemeful_site.h"

#undef NetworkIsolationKey

#endif // BRAVE_CHROMIUM_SRC_NET_BASE_SCHEMEFUL_SITE_H_
12 changes: 12 additions & 0 deletions chromium_src/net/http/transport_security_persister.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/* Copyright 2022 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */

#include "net/http/transport_security_persister.h"

// Use upstream version of TransportSerurityState to reference
// TransportSecurityState::Delegate without build issues.
#define TransportSecurityState TransportSecurityState_ChromiumImpl
#include "src/net/http/transport_security_persister.cc"
#undef TransportSecurityState
17 changes: 17 additions & 0 deletions chromium_src/net/http/transport_security_persister.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/* Copyright 2022 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */

#ifndef BRAVE_CHROMIUM_SRC_NET_HTTP_TRANSPORT_SECURITY_PERSISTER_H_
#define BRAVE_CHROMIUM_SRC_NET_HTTP_TRANSPORT_SECURITY_PERSISTER_H_

#include "net/http/transport_security_state.h"

// Use upstream version of TransportSerurityState to reference
// TransportSecurityState::Delegate without build issues.
#define TransportSecurityState TransportSecurityState_ChromiumImpl
#include "src/net/http/transport_security_persister.h"
#undef TransportSecurityState

#endif // BRAVE_CHROMIUM_SRC_NET_HTTP_TRANSPORT_SECURITY_PERSISTER_H_
205 changes: 205 additions & 0 deletions chromium_src/net/http/transport_security_state.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
#include "net/http/transport_security_state.h"

#include "build/build_config.h"
#include "net/base/network_isolation_key.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "url/gurl.h"
#include "url/url_util.h"

#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)

Expand All @@ -21,4 +25,205 @@

#endif

#define TransportSecurityState TransportSecurityState_ChromiumImpl

#include "src/net/http/transport_security_state.cc"

#undef BRAVE_ENABLE_STATIC_PINS

#undef TransportSecurityState

namespace net {

// Non-anonymous helper to friend with SchemefulSite.
class HSTSPartitionHashHelper {
public:
static std::string GetPartitionDomain(const SchemefulSite& schemeful_site) {
DCHECK(base::FeatureList::IsEnabled(features::kBravePartitionHSTS));
if (schemeful_site.has_registrable_domain_or_host()) {
return schemeful_site.registrable_domain_or_host();
}

if (schemeful_site.site_as_origin_.opaque()) {
std::string precursor_etld1_host =
registry_controlled_domains::GetDomainAndRegistry(
schemeful_site.site_as_origin_.GetTupleOrPrecursorTupleIfOpaque()
.host(),
registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
if (!precursor_etld1_host.empty()) {
return precursor_etld1_host;
}
}

return std::string();
}
};

namespace {

bool IsTopFrameOriginCryptographic(const IsolationInfo& isolation_info) {
return isolation_info.top_frame_origin() &&
GURL::SchemeIsCryptographic(
isolation_info.top_frame_origin()->scheme());
}

std::string GetHSTSPartitionHash(
const NetworkIsolationKey& network_isolation_key) {
DCHECK(base::FeatureList::IsEnabled(features::kBravePartitionHSTS));
// An empty top frame site cannot be used as a partition key, return an empty
// hash which will be treated as a non-persistable partition.
if (!network_isolation_key.GetTopFrameSite().has_value()) {
return std::string();
}

const std::string partition_domain =
HSTSPartitionHashHelper::GetPartitionDomain(
*network_isolation_key.GetTopFrameSite());
if (partition_domain.empty()) {
return std::string();
}

const std::string canonicalized_partition_domain =
CanonicalizeHost(partition_domain);
if (canonicalized_partition_domain.empty()) {
return std::string();
}

return HashHost(canonicalized_partition_domain);
}

// Use only top frame site as a key for HSTS partitioning to not over-populate
// HSTS state storage. Check top frame site for equality with site for cookies,
// don't store HSTS if it differs. IsolationInfo is not available everywhere,
// that's why we're using it only when parsing new HSTS state.
absl::optional<std::string> GetPartitionHashForAddingHSTS(
const IsolationInfo& isolation_info) {
if (!base::FeatureList::IsEnabled(features::kBravePartitionHSTS)) {
return absl::nullopt;
}

// If the top frame scheme is secure and SiteForCookies doesn't match
// TopFrameSite, then we don't want to store this HSTS state at all. Return an
// empty hash in this case, which will be treated as a non-persistable
// partition.
if (IsTopFrameOriginCryptographic(isolation_info) &&
isolation_info.site_for_cookies().site() !=
*isolation_info.network_isolation_key().GetTopFrameSite()) {
return std::string();
}

return GetHSTSPartitionHash(isolation_info.network_isolation_key());
}

// Use NetworkIsolationKey to create PartitionHash for accessing/storing data.
absl::optional<std::string> GetPartitionHashForHSTS(
const NetworkIsolationKey& network_isolation_key) {
if (!base::FeatureList::IsEnabled(features::kBravePartitionHSTS)) {
return absl::nullopt;
}
return GetHSTSPartitionHash(network_isolation_key);
}

// Use host-bound NetworkIsolationKey in cases when no NetworkIsolationKey is
// available. Such cases may include net-internals page, PasswordManager.
// All network::NetworkContext HSTS-related public methods will use this.
absl::optional<std::string> GetHostBoundPartitionHashForHSTS(
const std::string& host) {
if (!base::FeatureList::IsEnabled(features::kBravePartitionHSTS)) {
return absl::nullopt;
}
SchemefulSite schemeful_site(url::Origin::Create(GURL("https://" + host)));
NetworkIsolationKey network_isolation_key(schemeful_site, schemeful_site);
return GetHSTSPartitionHash(network_isolation_key);
}

} // namespace

bool TransportSecurityState::ShouldSSLErrorsBeFatal(
const NetworkIsolationKey& network_isolation_key,
const std::string& host) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
auto auto_reset_partition_hash = enabled_sts_hosts_.SetScopedPartitionHash(
GetPartitionHashForHSTS(network_isolation_key));
return TransportSecurityState_ChromiumImpl::ShouldSSLErrorsBeFatal(host);
}

bool TransportSecurityState::ShouldUpgradeToSSL(
const NetworkIsolationKey& network_isolation_key,
const std::string& host,
const NetLogWithSource& net_log) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
auto auto_reset_partition_hash = enabled_sts_hosts_.SetScopedPartitionHash(
GetPartitionHashForHSTS(network_isolation_key));
return TransportSecurityState_ChromiumImpl::ShouldUpgradeToSSL(host, net_log);
}

bool TransportSecurityState::AddHSTSHeader(const IsolationInfo& isolation_info,
const std::string& host,
const std::string& value) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
auto auto_reset_partition_hash = enabled_sts_hosts_.SetScopedPartitionHash(
GetPartitionHashForAddingHSTS(isolation_info));
if (enabled_sts_hosts_.HasPartitionHash() &&
!enabled_sts_hosts_.IsPartitionHashValid()) {
return false;
}
return TransportSecurityState_ChromiumImpl::AddHSTSHeader(host, value);
}

void TransportSecurityState::AddHSTS(const std::string& host,
const base::Time& expiry,
bool include_subdomains) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
auto auto_reset_partition_hash = enabled_sts_hosts_.SetScopedPartitionHash(
GetHostBoundPartitionHashForHSTS(host));
TransportSecurityState_ChromiumImpl::AddHSTS(host, expiry,
include_subdomains);
}

bool TransportSecurityState::ShouldSSLErrorsBeFatal(const std::string& host) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
auto auto_reset_partition_hash = enabled_sts_hosts_.SetScopedPartitionHash(
GetHostBoundPartitionHashForHSTS(host));
return TransportSecurityState_ChromiumImpl::ShouldSSLErrorsBeFatal(host);
}

bool TransportSecurityState::ShouldUpgradeToSSL(
const std::string& host,
const NetLogWithSource& net_log) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
auto auto_reset_partition_hash = enabled_sts_hosts_.SetScopedPartitionHash(
GetHostBoundPartitionHashForHSTS(host));
return TransportSecurityState_ChromiumImpl::ShouldUpgradeToSSL(host, net_log);
}

bool TransportSecurityState::GetDynamicSTSState(const std::string& host,
STSState* result) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
auto auto_reset_partition_hash = enabled_sts_hosts_.SetScopedPartitionHash(
GetHostBoundPartitionHashForHSTS(host));
return TransportSecurityState_ChromiumImpl::GetDynamicSTSState(host, result);
}

bool TransportSecurityState::DeleteDynamicDataForHost(const std::string& host) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
const bool chromium_deleted =
TransportSecurityState_ChromiumImpl::DeleteDynamicDataForHost(host);

bool brave_deleted = false;
if (base::FeatureList::IsEnabled(features::kBravePartitionHSTS)) {
const std::string canonicalized_host = CanonicalizeHost(host);
if (!canonicalized_host.empty()) {
if (enabled_sts_hosts_.DeleteDataInAllPartitions(
HashHost(canonicalized_host))) {
brave_deleted = true;
}
}
}

if (brave_deleted)
DirtyNotify();
return chromium_deleted || brave_deleted;
}

} // namespace net
60 changes: 60 additions & 0 deletions chromium_src/net/http/transport_security_state.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/* Copyright 2022 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */

#ifndef BRAVE_CHROMIUM_SRC_NET_HTTP_TRANSPORT_SECURITY_STATE_H_
#define BRAVE_CHROMIUM_SRC_NET_HTTP_TRANSPORT_SECURITY_STATE_H_

#include "brave/net/http/partitioned_host_state_map.h"
#include "net/base/isolation_info.h"

namespace net {
class TransportSecurityState;
using TransportSecurityState_BraveImpl = TransportSecurityState;
} // namespace net

#define TransportSecurityState TransportSecurityState_ChromiumImpl

#define enabled_sts_hosts_ \
enabled_sts_hosts_unused_; \
friend TransportSecurityState_BraveImpl; \
PartitionedHostStateMap<STSStateMap> enabled_sts_hosts_

#include "src/net/http/transport_security_state.h"

#undef enabled_sts_hosts_
#undef TransportSecurityState

namespace net {

class NET_EXPORT TransportSecurityState
: public TransportSecurityState_ChromiumImpl {
public:
using TransportSecurityState_ChromiumImpl::
TransportSecurityState_ChromiumImpl;

bool ShouldSSLErrorsBeFatal(const NetworkIsolationKey& network_isolation_key,
const std::string& host);
bool ShouldUpgradeToSSL(const NetworkIsolationKey& network_isolation_key,
const std::string& host,
const NetLogWithSource& net_log = NetLogWithSource());
bool AddHSTSHeader(const IsolationInfo& isolation_info,
const std::string& host,
const std::string& value);

// This is used only for manual adding via net-internals page.
void AddHSTS(const std::string& host,
const base::Time& expiry,
bool include_subdomains);
// These are used in some places where no NIK is available.
bool ShouldSSLErrorsBeFatal(const std::string& host);
bool ShouldUpgradeToSSL(const std::string& host,
const NetLogWithSource& net_log = NetLogWithSource());
bool GetDynamicSTSState(const std::string& host, STSState* result);
bool DeleteDynamicDataForHost(const std::string& host);
};

} // namespace net

#endif // BRAVE_CHROMIUM_SRC_NET_HTTP_TRANSPORT_SECURITY_STATE_H_
13 changes: 13 additions & 0 deletions chromium_src/net/quic/crypto/proof_verifier_chromium.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/* Copyright 2022 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "net/http/transport_security_state.h"

#define ShouldSSLErrorsBeFatal(host) \
ShouldSSLErrorsBeFatal(proof_verifier_->network_isolation_key_, host)

#include "src/net/quic/crypto/proof_verifier_chromium.cc"

#undef ShouldSSLErrorsBeFatal
13 changes: 13 additions & 0 deletions chromium_src/net/socket/ssl_client_socket_impl.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/* Copyright 2022 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "net/http/transport_security_state.h"

#define ShouldSSLErrorsBeFatal(host) \
ShouldSSLErrorsBeFatal(ssl_config_.network_isolation_key, host)

#include "src/net/socket/ssl_client_socket_impl.cc"

#undef ShouldSSLErrorsBeFatal
15 changes: 15 additions & 0 deletions chromium_src/net/url_request/url_request_http_job.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,23 @@

#include "net/url_request/url_request_http_job.h"

#include "net/http/transport_security_state.h"

#define ShouldSSLErrorsBeFatal(host) \
ShouldSSLErrorsBeFatal(request_->isolation_info().network_isolation_key(), \
host)
#define ShouldUpgradeToSSL(host, net_log) \
ShouldUpgradeToSSL(request->isolation_info().network_isolation_key(), host, \
net_log)
#define AddHSTSHeader(host, value) \
AddHSTSHeader(request_->isolation_info(), host, value)

#include "src/net/url_request/url_request_http_job.cc"

#undef AddHSTSHeader
#undef ShouldUpgradeToSSL
#undef ShouldSSLErrorsBeFatal

namespace net {

CookieOptions URLRequestHttpJob::CreateCookieOptions(
Expand Down
Loading

0 comments on commit 1100f7b

Please sign in to comment.