Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add partitioned HSTS storage support. #13062

Merged
merged 5 commits into from
May 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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();
}
goodov marked this conversation as resolved.
Show resolved Hide resolved

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