• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 #include "net/base/network_anonymization_key.h"
5 #include "base/feature_list.h"
6 #include "base/unguessable_token.h"
7 #include "base/values.h"
8 #include "net/base/features.h"
9 #include "net/base/net_export.h"
10 #include "net/base/network_isolation_key.h"
11 #include "net/base/schemeful_site.h"
12 #include "net/cookies/site_for_cookies.h"
13 #include "third_party/abseil-cpp/absl/types/optional.h"
14 
15 namespace net {
16 
17 namespace {
18 
19 // True if network state partitioning should be enabled regardless of feature
20 // settings.
21 bool g_partition_by_default = false;
22 
23 // True if NAK::IsPartitioningEnabled has been called, and the value of
24 // `g_partition_by_default` cannot be changed.
25 bool g_partition_by_default_locked = false;
26 
27 }  // namespace
28 
NetworkAnonymizationKey(const SchemefulSite & top_frame_site,bool is_cross_site,absl::optional<base::UnguessableToken> nonce)29 NetworkAnonymizationKey::NetworkAnonymizationKey(
30     const SchemefulSite& top_frame_site,
31     bool is_cross_site,
32     absl::optional<base::UnguessableToken> nonce)
33     : top_frame_site_(top_frame_site),
34       is_cross_site_(is_cross_site),
35       nonce_(nonce) {
36   DCHECK(top_frame_site_.has_value());
37 }
38 
CreateFromFrameSite(const SchemefulSite & top_frame_site,const SchemefulSite & frame_site,absl::optional<base::UnguessableToken> nonce)39 NetworkAnonymizationKey NetworkAnonymizationKey::CreateFromFrameSite(
40     const SchemefulSite& top_frame_site,
41     const SchemefulSite& frame_site,
42     absl::optional<base::UnguessableToken> nonce) {
43   bool is_cross_site = top_frame_site != frame_site;
44   return NetworkAnonymizationKey(top_frame_site, is_cross_site, nonce);
45 }
46 
CreateFromNetworkIsolationKey(const net::NetworkIsolationKey & network_isolation_key)47 NetworkAnonymizationKey NetworkAnonymizationKey::CreateFromNetworkIsolationKey(
48     const net::NetworkIsolationKey& network_isolation_key) {
49   // We cannot create a valid NetworkAnonymizationKey from a NetworkIsolationKey
50   // that is not fully populated.
51   if (!network_isolation_key.IsFullyPopulated()) {
52     return NetworkAnonymizationKey();
53   }
54 
55   switch (NetworkIsolationKey::GetMode()) {
56     case NetworkIsolationKey::Mode::kFrameSiteEnabled:
57       return CreateFromFrameSite(
58           network_isolation_key.GetTopFrameSite().value(),
59           network_isolation_key.GetFrameSite().value(),
60           network_isolation_key.GetNonce());
61     case NetworkIsolationKey::Mode::kCrossSiteFlagEnabled:
62       return NetworkAnonymizationKey(
63           network_isolation_key.GetTopFrameSite().value(),
64           network_isolation_key.GetIsCrossSite().value(),
65           network_isolation_key.GetNonce());
66   }
67 }
68 
NetworkAnonymizationKey()69 NetworkAnonymizationKey::NetworkAnonymizationKey()
70     : top_frame_site_(absl::nullopt),
71       is_cross_site_(false),
72       nonce_(absl::nullopt) {}
73 
74 NetworkAnonymizationKey::NetworkAnonymizationKey(
75     const NetworkAnonymizationKey& network_anonymization_key) = default;
76 
77 NetworkAnonymizationKey::NetworkAnonymizationKey(
78     NetworkAnonymizationKey&& network_anonymization_key) = default;
79 
80 NetworkAnonymizationKey::~NetworkAnonymizationKey() = default;
81 
82 NetworkAnonymizationKey& NetworkAnonymizationKey::operator=(
83     const NetworkAnonymizationKey& network_anonymization_key) = default;
84 
85 NetworkAnonymizationKey& NetworkAnonymizationKey::operator=(
86     NetworkAnonymizationKey&& network_anonymization_key) = default;
87 
CreateTransient()88 NetworkAnonymizationKey NetworkAnonymizationKey::CreateTransient() {
89   SchemefulSite site_with_opaque_origin;
90   return NetworkAnonymizationKey(site_with_opaque_origin, false);
91 }
92 
ToDebugString() const93 std::string NetworkAnonymizationKey::ToDebugString() const {
94   if (!IsFullyPopulated()) {
95     return "null";
96   }
97 
98   std::string str = GetSiteDebugString(top_frame_site_);
99   str += IsCrossSite() ? " cross_site" : " same_site";
100 
101   // Currently, if the NAK has a nonce it will be marked transient. For debug
102   // purposes we will print the value but if called via
103   // `NetworkAnonymizationKey::ToString` we will have already returned "".
104   if (nonce_.has_value()) {
105     str += " (with nonce " + nonce_->ToString() + ")";
106   }
107 
108   return str;
109 }
110 
IsEmpty() const111 bool NetworkAnonymizationKey::IsEmpty() const {
112   return !top_frame_site_.has_value();
113 }
114 
IsFullyPopulated() const115 bool NetworkAnonymizationKey::IsFullyPopulated() const {
116   return top_frame_site_.has_value();
117 }
118 
IsTransient() const119 bool NetworkAnonymizationKey::IsTransient() const {
120   if (!IsFullyPopulated())
121     return true;
122 
123   return top_frame_site_->opaque() || nonce_.has_value();
124 }
125 
ToValue(base::Value * out_value) const126 bool NetworkAnonymizationKey::ToValue(base::Value* out_value) const {
127   if (IsEmpty()) {
128     *out_value = base::Value(base::Value::Type::LIST);
129     return true;
130   }
131 
132   if (IsTransient())
133     return false;
134 
135   absl::optional<std::string> top_frame_value =
136       SerializeSiteWithNonce(*top_frame_site_);
137   if (!top_frame_value)
138     return false;
139   base::Value::List list;
140   list.Append(std::move(top_frame_value).value());
141 
142   list.Append(IsCrossSite());
143 
144   *out_value = base::Value(std::move(list));
145   return true;
146 }
147 
FromValue(const base::Value & value,NetworkAnonymizationKey * network_anonymization_key)148 bool NetworkAnonymizationKey::FromValue(
149     const base::Value& value,
150     NetworkAnonymizationKey* network_anonymization_key) {
151   if (!value.is_list()) {
152     return false;
153   }
154 
155   const base::Value::List& list = value.GetList();
156   if (list.empty()) {
157     *network_anonymization_key = NetworkAnonymizationKey();
158     return true;
159   }
160 
161   // Check the format.
162   if (list.size() != 2 || !list[0].is_string() || !list[1].is_bool()) {
163     return false;
164   }
165 
166   // Check top_level_site is valid for any key scheme
167   absl::optional<SchemefulSite> top_frame_site =
168       SchemefulSite::DeserializeWithNonce(list[0].GetString());
169   if (!top_frame_site) {
170     return false;
171   }
172 
173   bool is_cross_site = list[1].GetBool();
174 
175   *network_anonymization_key =
176       NetworkAnonymizationKey(top_frame_site.value(), is_cross_site);
177   return true;
178 }
179 
GetSiteDebugString(const absl::optional<SchemefulSite> & site) const180 std::string NetworkAnonymizationKey::GetSiteDebugString(
181     const absl::optional<SchemefulSite>& site) const {
182   return site ? site->GetDebugString() : "null";
183 }
184 
SerializeSiteWithNonce(const SchemefulSite & site)185 absl::optional<std::string> NetworkAnonymizationKey::SerializeSiteWithNonce(
186     const SchemefulSite& site) {
187   return *(const_cast<SchemefulSite&>(site).SerializeWithNonce());
188 }
189 
190 // static
IsPartitioningEnabled()191 bool NetworkAnonymizationKey::IsPartitioningEnabled() {
192   g_partition_by_default_locked = true;
193   return g_partition_by_default ||
194          base::FeatureList::IsEnabled(
195              features::kSplitHostCacheByNetworkIsolationKey) ||
196          base::FeatureList::IsEnabled(
197              features::kPartitionConnectionsByNetworkIsolationKey) ||
198          base::FeatureList::IsEnabled(
199              features::kPartitionHttpServerPropertiesByNetworkIsolationKey) ||
200          base::FeatureList::IsEnabled(
201              features::kPartitionSSLSessionsByNetworkIsolationKey) ||
202          base::FeatureList::IsEnabled(
203              features::kPartitionNelAndReportingByNetworkIsolationKey);
204 }
205 
206 // static
PartitionByDefault()207 void NetworkAnonymizationKey::PartitionByDefault() {
208   DCHECK(!g_partition_by_default_locked);
209   // Only set the global if none of the relevant features are overridden.
210   if (!base::FeatureList::GetInstance()->IsFeatureOverridden(
211           "SplitHostCacheByNetworkIsolationKey") &&
212       !base::FeatureList::GetInstance()->IsFeatureOverridden(
213           "PartitionConnectionsByNetworkIsolationKey") &&
214       !base::FeatureList::GetInstance()->IsFeatureOverridden(
215           "PartitionHttpServerPropertiesByNetworkIsolationKey") &&
216       !base::FeatureList::GetInstance()->IsFeatureOverridden(
217           "PartitionSSLSessionsByNetworkIsolationKey") &&
218       !base::FeatureList::GetInstance()->IsFeatureOverridden(
219           "PartitionNelAndReportingByNetworkIsolationKey")) {
220     g_partition_by_default = true;
221   }
222 }
223 
224 // static
ClearGlobalsForTesting()225 void NetworkAnonymizationKey::ClearGlobalsForTesting() {
226   g_partition_by_default = false;
227   g_partition_by_default_locked = false;
228 }
229 
230 }  // namespace net
231