1*6777b538SAndroid Build Coastguard Worker // Copyright 2021 The Chromium Authors 2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be 3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file. 4*6777b538SAndroid Build Coastguard Worker 5*6777b538SAndroid Build Coastguard Worker #ifndef NET_COOKIES_COOKIE_PARTITION_KEY_H_ 6*6777b538SAndroid Build Coastguard Worker #define NET_COOKIES_COOKIE_PARTITION_KEY_H_ 7*6777b538SAndroid Build Coastguard Worker 8*6777b538SAndroid Build Coastguard Worker #include <optional> 9*6777b538SAndroid Build Coastguard Worker #include <string> 10*6777b538SAndroid Build Coastguard Worker 11*6777b538SAndroid Build Coastguard Worker #include "base/types/expected.h" 12*6777b538SAndroid Build Coastguard Worker #include "net/base/cronet_buildflags.h" 13*6777b538SAndroid Build Coastguard Worker #include "net/base/features.h" 14*6777b538SAndroid Build Coastguard Worker #include "net/base/net_export.h" 15*6777b538SAndroid Build Coastguard Worker #include "net/base/network_isolation_key.h" 16*6777b538SAndroid Build Coastguard Worker #include "net/base/schemeful_site.h" 17*6777b538SAndroid Build Coastguard Worker #include "net/cookies/site_for_cookies.h" 18*6777b538SAndroid Build Coastguard Worker #include "url/gurl.h" 19*6777b538SAndroid Build Coastguard Worker 20*6777b538SAndroid Build Coastguard Worker #if !BUILDFLAG(CRONET_BUILD) 21*6777b538SAndroid Build Coastguard Worker #include "mojo/public/cpp/bindings/default_construct_tag.h" 22*6777b538SAndroid Build Coastguard Worker #endif 23*6777b538SAndroid Build Coastguard Worker 24*6777b538SAndroid Build Coastguard Worker namespace net { 25*6777b538SAndroid Build Coastguard Worker 26*6777b538SAndroid Build Coastguard Worker class NET_EXPORT CookiePartitionKey { 27*6777b538SAndroid Build Coastguard Worker public: 28*6777b538SAndroid Build Coastguard Worker class NET_EXPORT SerializedCookiePartitionKey { 29*6777b538SAndroid Build Coastguard Worker public: 30*6777b538SAndroid Build Coastguard Worker const std::string& TopLevelSite() const; 31*6777b538SAndroid Build Coastguard Worker bool has_cross_site_ancestor() const; 32*6777b538SAndroid Build Coastguard Worker 33*6777b538SAndroid Build Coastguard Worker private: 34*6777b538SAndroid Build Coastguard Worker friend class CookiePartitionKey; 35*6777b538SAndroid Build Coastguard Worker // This constructor does not check if the values being serialized are valid. 36*6777b538SAndroid Build Coastguard Worker // The caller of this function must ensure that only valid values are passed 37*6777b538SAndroid Build Coastguard Worker // to this method. 38*6777b538SAndroid Build Coastguard Worker explicit SerializedCookiePartitionKey(const std::string& site, 39*6777b538SAndroid Build Coastguard Worker bool has_cross_site_ancestor); 40*6777b538SAndroid Build Coastguard Worker 41*6777b538SAndroid Build Coastguard Worker std::string top_level_site_; 42*6777b538SAndroid Build Coastguard Worker bool has_cross_site_ancestor_; 43*6777b538SAndroid Build Coastguard Worker }; 44*6777b538SAndroid Build Coastguard Worker 45*6777b538SAndroid Build Coastguard Worker // An enumerated value representing whether any frame in the PartitionKey's 46*6777b538SAndroid Build Coastguard Worker // ancestor chain (including the top-level document's site) is cross-site with 47*6777b538SAndroid Build Coastguard Worker // the current frame. These values are persisted to disk. Entries should not 48*6777b538SAndroid Build Coastguard Worker // be renumbered and numeric values should never be reused. 49*6777b538SAndroid Build Coastguard Worker enum class AncestorChainBit { 50*6777b538SAndroid Build Coastguard Worker // All frames in the ancestor chain are pairwise same-site. 51*6777b538SAndroid Build Coastguard Worker kSameSite = 0, 52*6777b538SAndroid Build Coastguard Worker // At least one frame in the ancestor chain is cross-site with 53*6777b538SAndroid Build Coastguard Worker // the current frame. 54*6777b538SAndroid Build Coastguard Worker kCrossSite = 1, 55*6777b538SAndroid Build Coastguard Worker }; 56*6777b538SAndroid Build Coastguard Worker 57*6777b538SAndroid Build Coastguard Worker static AncestorChainBit BoolToAncestorChainBit(bool val); 58*6777b538SAndroid Build Coastguard Worker 59*6777b538SAndroid Build Coastguard Worker CookiePartitionKey() = delete; 60*6777b538SAndroid Build Coastguard Worker #if !BUILDFLAG(CRONET_BUILD) 61*6777b538SAndroid Build Coastguard Worker explicit CookiePartitionKey(mojo::DefaultConstruct::Tag); 62*6777b538SAndroid Build Coastguard Worker #endif 63*6777b538SAndroid Build Coastguard Worker CookiePartitionKey(const CookiePartitionKey& other); 64*6777b538SAndroid Build Coastguard Worker CookiePartitionKey(CookiePartitionKey&& other); 65*6777b538SAndroid Build Coastguard Worker CookiePartitionKey& operator=(const CookiePartitionKey& other); 66*6777b538SAndroid Build Coastguard Worker CookiePartitionKey& operator=(CookiePartitionKey&& other); 67*6777b538SAndroid Build Coastguard Worker ~CookiePartitionKey(); 68*6777b538SAndroid Build Coastguard Worker 69*6777b538SAndroid Build Coastguard Worker bool operator==(const CookiePartitionKey& other) const; 70*6777b538SAndroid Build Coastguard Worker bool operator!=(const CookiePartitionKey& other) const; 71*6777b538SAndroid Build Coastguard Worker bool operator<(const CookiePartitionKey& other) const; 72*6777b538SAndroid Build Coastguard Worker 73*6777b538SAndroid Build Coastguard Worker // Methods for serializing and deserializing a partition key to/from a string. 74*6777b538SAndroid Build Coastguard Worker // This is currently used for: 75*6777b538SAndroid Build Coastguard Worker // - Storing persistent partitioned cookies 76*6777b538SAndroid Build Coastguard Worker // - Loading partitioned cookies into Java code 77*6777b538SAndroid Build Coastguard Worker // - Sending cookie partition keys as strings in the DevTools protocol 78*6777b538SAndroid Build Coastguard Worker // 79*6777b538SAndroid Build Coastguard Worker // This function returns true if the partition key is not opaque and if nonce_ 80*6777b538SAndroid Build Coastguard Worker // is not present. We do not want to serialize cookies with opaque origins or 81*6777b538SAndroid Build Coastguard Worker // nonce in their partition key to disk, because if the browser session ends 82*6777b538SAndroid Build Coastguard Worker // we will not be able to attach the saved cookie to any future requests. This 83*6777b538SAndroid Build Coastguard Worker // is because opaque origins' nonces are only stored in volatile memory. 84*6777b538SAndroid Build Coastguard Worker // 85*6777b538SAndroid Build Coastguard Worker // TODO(crbug.com/1225444) Investigate ways to persist partition keys with 86*6777b538SAndroid Build Coastguard Worker // opaque origins if a browser session is restored. 87*6777b538SAndroid Build Coastguard Worker [[nodiscard]] static base::expected<SerializedCookiePartitionKey, std::string> 88*6777b538SAndroid Build Coastguard Worker Serialize(const std::optional<CookiePartitionKey>& in); 89*6777b538SAndroid Build Coastguard Worker 90*6777b538SAndroid Build Coastguard Worker static CookiePartitionKey FromURLForTesting( 91*6777b538SAndroid Build Coastguard Worker const GURL& url, 92*6777b538SAndroid Build Coastguard Worker AncestorChainBit ancestor_chain_bit = AncestorChainBit::kCrossSite, 93*6777b538SAndroid Build Coastguard Worker std::optional<base::UnguessableToken> nonce = std::nullopt) { 94*6777b538SAndroid Build Coastguard Worker return CookiePartitionKey(SchemefulSite(url), nonce, ancestor_chain_bit); 95*6777b538SAndroid Build Coastguard Worker } 96*6777b538SAndroid Build Coastguard Worker 97*6777b538SAndroid Build Coastguard Worker // Create a partition key from a network isolation key. Partition key is 98*6777b538SAndroid Build Coastguard Worker // derived from the key's top-frame site. For scripts, the request_site 99*6777b538SAndroid Build Coastguard Worker // is the url of the context running the code. 100*6777b538SAndroid Build Coastguard Worker static std::optional<CookiePartitionKey> FromNetworkIsolationKey( 101*6777b538SAndroid Build Coastguard Worker const NetworkIsolationKey& network_isolation_key, 102*6777b538SAndroid Build Coastguard Worker SiteForCookies site_for_cookies, 103*6777b538SAndroid Build Coastguard Worker SchemefulSite request_site); 104*6777b538SAndroid Build Coastguard Worker 105*6777b538SAndroid Build Coastguard Worker // Create a new CookiePartitionKey from the site of an existing 106*6777b538SAndroid Build Coastguard Worker // CookiePartitionKey. This should only be used for sites of partition keys 107*6777b538SAndroid Build Coastguard Worker // which were already created using Deserialize or FromNetworkIsolationKey. 108*6777b538SAndroid Build Coastguard Worker static CookiePartitionKey FromWire( 109*6777b538SAndroid Build Coastguard Worker const SchemefulSite& site, 110*6777b538SAndroid Build Coastguard Worker AncestorChainBit ancestor_chain_bit, 111*6777b538SAndroid Build Coastguard Worker std::optional<base::UnguessableToken> nonce = std::nullopt) { 112*6777b538SAndroid Build Coastguard Worker return CookiePartitionKey(site, nonce, ancestor_chain_bit); 113*6777b538SAndroid Build Coastguard Worker } 114*6777b538SAndroid Build Coastguard Worker 115*6777b538SAndroid Build Coastguard Worker // Create a new CookiePartitionKey in a script running in a renderer. We do 116*6777b538SAndroid Build Coastguard Worker // not trust the renderer to provide us with a cookie partition key, so we let 117*6777b538SAndroid Build Coastguard Worker // the renderer use this method to indicate the cookie is partitioned but the 118*6777b538SAndroid Build Coastguard Worker // key still needs to be determined. 119*6777b538SAndroid Build Coastguard Worker // 120*6777b538SAndroid Build Coastguard Worker // When the browser is ingesting cookie partition keys from the renderer, 121*6777b538SAndroid Build Coastguard Worker // either the `from_script_` flag should be set or the cookie partition key 122*6777b538SAndroid Build Coastguard Worker // should match the browser's. Otherwise the renderer may be compromised. 123*6777b538SAndroid Build Coastguard Worker // 124*6777b538SAndroid Build Coastguard Worker // TODO(crbug.com/1225444) Consider removing this factory method and 125*6777b538SAndroid Build Coastguard Worker // `from_script_` flag when BlinkStorageKey is available in 126*6777b538SAndroid Build Coastguard Worker // ServiceWorkerGlobalScope. FromScript()127*6777b538SAndroid Build Coastguard Worker static std::optional<CookiePartitionKey> FromScript() { 128*6777b538SAndroid Build Coastguard Worker return std::make_optional(CookiePartitionKey(true)); 129*6777b538SAndroid Build Coastguard Worker } 130*6777b538SAndroid Build Coastguard Worker 131*6777b538SAndroid Build Coastguard Worker // Create a new CookiePartitionKey from the components of a StorageKey. 132*6777b538SAndroid Build Coastguard Worker // Forwards to FromWire, but unlike that method in this one the optional nonce 133*6777b538SAndroid Build Coastguard Worker // argument has no default. It also checks that cookie partitioning is enabled 134*6777b538SAndroid Build Coastguard Worker // before returning a valid key, which FromWire does not check. 135*6777b538SAndroid Build Coastguard Worker [[nodiscard]] static std::optional<CookiePartitionKey> 136*6777b538SAndroid Build Coastguard Worker FromStorageKeyComponents(const SchemefulSite& top_level_site, 137*6777b538SAndroid Build Coastguard Worker AncestorChainBit ancestor_chain_bit, 138*6777b538SAndroid Build Coastguard Worker const std::optional<base::UnguessableToken>& nonce); 139*6777b538SAndroid Build Coastguard Worker 140*6777b538SAndroid Build Coastguard Worker // FromStorage is a factory method which is meant for creating a new 141*6777b538SAndroid Build Coastguard Worker // CookiePartitionKey using properties of a previously existing 142*6777b538SAndroid Build Coastguard Worker // CookiePartitionKey that was already ingested into storage. This should NOT 143*6777b538SAndroid Build Coastguard Worker // be used to create a new CookiePartitionKey that was not previously saved in 144*6777b538SAndroid Build Coastguard Worker // storage. 145*6777b538SAndroid Build Coastguard Worker [[nodiscard]] static base::expected<std::optional<CookiePartitionKey>, 146*6777b538SAndroid Build Coastguard Worker std::string> 147*6777b538SAndroid Build Coastguard Worker FromStorage(const std::string& top_level_site, bool has_cross_site_ancestor); 148*6777b538SAndroid Build Coastguard Worker 149*6777b538SAndroid Build Coastguard Worker // This method should be used when the data provided is expected to be 150*6777b538SAndroid Build Coastguard Worker // non-null but might be invalid or comes from a potentially untrustworthy 151*6777b538SAndroid Build Coastguard Worker // source (such as user-supplied data). 152*6777b538SAndroid Build Coastguard Worker // 153*6777b538SAndroid Build Coastguard Worker // This reserves FromStorage to handle cases that can result in a null key 154*6777b538SAndroid Build Coastguard Worker // (and perfectly validly, like in the case when the top_level_site is empty). 155*6777b538SAndroid Build Coastguard Worker [[nodiscard]] static base::expected<CookiePartitionKey, std::string> 156*6777b538SAndroid Build Coastguard Worker FromUntrustedInput(const std::string& top_level_site, 157*6777b538SAndroid Build Coastguard Worker bool has_cross_site_ancestor); 158*6777b538SAndroid Build Coastguard Worker site()159*6777b538SAndroid Build Coastguard Worker const SchemefulSite& site() const { return site_; } 160*6777b538SAndroid Build Coastguard Worker from_script()161*6777b538SAndroid Build Coastguard Worker bool from_script() const { return from_script_; } 162*6777b538SAndroid Build Coastguard Worker 163*6777b538SAndroid Build Coastguard Worker // Returns true if the current partition key can be serialized to a string. 164*6777b538SAndroid Build Coastguard Worker // Cookie partition keys whose internal site is opaque cannot be serialized. 165*6777b538SAndroid Build Coastguard Worker bool IsSerializeable() const; 166*6777b538SAndroid Build Coastguard Worker nonce()167*6777b538SAndroid Build Coastguard Worker const std::optional<base::UnguessableToken>& nonce() const { return nonce_; } 168*6777b538SAndroid Build Coastguard Worker HasNonce(const std::optional<CookiePartitionKey> & key)169*6777b538SAndroid Build Coastguard Worker static bool HasNonce(const std::optional<CookiePartitionKey>& key) { 170*6777b538SAndroid Build Coastguard Worker return key && key->nonce(); 171*6777b538SAndroid Build Coastguard Worker } 172*6777b538SAndroid Build Coastguard Worker IsThirdParty()173*6777b538SAndroid Build Coastguard Worker bool IsThirdParty() const { 174*6777b538SAndroid Build Coastguard Worker return ancestor_chain_bit_ == AncestorChainBit::kCrossSite; 175*6777b538SAndroid Build Coastguard Worker } 176*6777b538SAndroid Build Coastguard Worker 177*6777b538SAndroid Build Coastguard Worker private: 178*6777b538SAndroid Build Coastguard Worker explicit CookiePartitionKey(const SchemefulSite& site, 179*6777b538SAndroid Build Coastguard Worker std::optional<base::UnguessableToken> nonce, 180*6777b538SAndroid Build Coastguard Worker AncestorChainBit ancestor_chain_bit); 181*6777b538SAndroid Build Coastguard Worker explicit CookiePartitionKey(bool from_script); 182*6777b538SAndroid Build Coastguard Worker 183*6777b538SAndroid Build Coastguard Worker // This method holds the deserialization logic for validating input from 184*6777b538SAndroid Build Coastguard Worker // DeserializeForTesting and FromUntrustedInput which can be used to pass 185*6777b538SAndroid Build Coastguard Worker // unserializable top_level_site values. 186*6777b538SAndroid Build Coastguard Worker [[nodiscard]] static base::expected<CookiePartitionKey, std::string> 187*6777b538SAndroid Build Coastguard Worker DeserializeInternal( 188*6777b538SAndroid Build Coastguard Worker const std::string& top_level_site, 189*6777b538SAndroid Build Coastguard Worker CookiePartitionKey::AncestorChainBit has_cross_site_ancestor); 190*6777b538SAndroid Build Coastguard Worker 191*6777b538SAndroid Build Coastguard Worker AncestorChainBit MaybeAncestorChainBit() const; 192*6777b538SAndroid Build Coastguard Worker 193*6777b538SAndroid Build Coastguard Worker SchemefulSite site_; 194*6777b538SAndroid Build Coastguard Worker bool from_script_ = false; 195*6777b538SAndroid Build Coastguard Worker // crbug.com/328043119 remove code associated with 196*6777b538SAndroid Build Coastguard Worker // kAncestorChainBitEnabledInPartitionedCookies 197*6777b538SAndroid Build Coastguard Worker // when feature is no longer needed. 198*6777b538SAndroid Build Coastguard Worker bool ancestor_chain_enabled_ = base::FeatureList::IsEnabled( 199*6777b538SAndroid Build Coastguard Worker features::kAncestorChainBitEnabledInPartitionedCookies); 200*6777b538SAndroid Build Coastguard Worker 201*6777b538SAndroid Build Coastguard Worker // Having a nonce is a way to force a transient opaque `CookiePartitionKey` 202*6777b538SAndroid Build Coastguard Worker // for non-opaque origins. 203*6777b538SAndroid Build Coastguard Worker std::optional<base::UnguessableToken> nonce_; 204*6777b538SAndroid Build Coastguard Worker AncestorChainBit ancestor_chain_bit_ = AncestorChainBit::kCrossSite; 205*6777b538SAndroid Build Coastguard Worker }; 206*6777b538SAndroid Build Coastguard Worker 207*6777b538SAndroid Build Coastguard Worker // Used so that CookiePartitionKeys can be the arguments of DCHECK_EQ. 208*6777b538SAndroid Build Coastguard Worker NET_EXPORT std::ostream& operator<<(std::ostream& os, 209*6777b538SAndroid Build Coastguard Worker const CookiePartitionKey& cpk); 210*6777b538SAndroid Build Coastguard Worker 211*6777b538SAndroid Build Coastguard Worker } // namespace net 212*6777b538SAndroid Build Coastguard Worker 213*6777b538SAndroid Build Coastguard Worker #endif // NET_COOKIES_COOKIE_PARTITION_KEY_H_ 214