Browse Source

feat: add experimental cookie encryption support (#29493)

* feat: add experimental cookie encryption support (#27524)

* feat: add experimental cookie encryption support on macOS

* chore: fix TODO

* update patches

* feat: make cookie encryption work on windows

* chore: update cookie encryption support comments

* fix: only call OSCrypt::Init on windows

* chore: make cookie encryption work on linux

* Update shell/browser/net/system_network_context_manager.cc

Co-authored-by: Jeremy Rose <[email protected]>

* chore: fix lint

* chore: update patches

* chore: update patches to upstreamed variants

* chore: use chrome ::switches constants

* chore: remove bad patch

* build: disable cookie encryption by default

* chore: update patches

* fix: provide std::string to NoDestructor

* chore: fix macos, nodestructor syntax

* build: fix macOS build due to mismatch in DEFINE

Co-authored-by: Electron Bot <[email protected]>
Co-authored-by: Jeremy Rose <[email protected]>

* chore: update patches

Co-authored-by: Electron Bot <[email protected]>
Co-authored-by: Jeremy Rose <[email protected]>
Samuel Attard 3 years ago
parent
commit
2156a9064f

+ 7 - 1
BUILD.gn

@@ -1,6 +1,7 @@
 import("//build/config/locales.gni")
 import("//build/config/ui.gni")
 import("//build/config/win/manifest.gni")
+import("//components/os_crypt/features.gni")
 import("//components/spellcheck/spellcheck_build_features.gni")
 import("//content/public/app/mac_helpers.gni")
 import("//extensions/buildflags/buildflags.gni")
@@ -292,7 +293,7 @@ templated_file("electron_version_header") {
 action("electron_fuses") {
   script = "build/fuses/build.py"
 
-  inputs = [ "build/fuses/fuses.json" ]
+  inputs = [ "build/fuses/fuses.json5" ]
 
   outputs = [
     "$target_gen_dir/fuses.h",
@@ -331,6 +332,7 @@ source_set("electron_lib") {
     "//components/network_hints/common:mojo_bindings",
     "//components/network_hints/renderer",
     "//components/network_session_configurator/common",
+    "//components/os_crypt",
     "//components/pref_registry",
     "//components/prefs",
     "//components/upload_list",
@@ -678,6 +680,10 @@ source_set("electron_lib") {
     ]
     libs += [ "uxtheme.lib" ]
   }
+
+  if (allow_runtime_configurable_key_storage) {
+    defines += [ "ALLOW_RUNTIME_CONFIGURABLE_KEY_STORAGE" ]
+  }
 }
 
 electron_paks("packed_resources") {

+ 3 - 0
build/args/all.gn

@@ -28,3 +28,6 @@ libcxx_abi_unstable = false
 enable_pseudolocales = false
 
 is_cfi = false
+
+# Make application name configurable at runtime for cookie crypto
+allow_runtime_configurable_key_storage = true

+ 2 - 2
build/fuses/build.py

@@ -49,8 +49,8 @@ const volatile char kFuseWire[] = { /* sentinel */ {sentinel}, /* fuse_version *
 }
 """
 
-with open(os.path.join(dir_path, "fuses.json"), 'r') as f:
-  fuse_defaults = json.load(f)
+with open(os.path.join(dir_path, "fuses.json5"), 'r') as f:
+  fuse_defaults = json.loads(''.join(line for line in f.readlines() if not line.strip()[0] == "/"))
 
 fuse_version = fuse_defaults['_version']
 del fuse_defaults['_version']

+ 2 - 1
build/fuses/fuses.json → build/fuses/fuses.json5

@@ -2,5 +2,6 @@
   "_comment": "Modifying the fuse schema in any breaking way should result in the _version prop being incremented.  NEVER remove a fuse or change its meaning, instead mark it as removed with 'r'",
   "_schema": "0 == off, 1 == on, r == removed fuse",
   "_version": 1,
-  "run_as_node": "1"
+  "run_as_node": "1",
+  "cookie_encryption": "0"
 }

+ 1 - 1
docs/tutorial/fuses.md

@@ -51,4 +51,4 @@ Somewhere in the Electron binary there will be a sequence of bytes that look lik
 
 To flip a fuse you find its position in the fuse wire and change it to "0" or "1" depending on the state you'd like.
 
-You can view the current schema [here](https://github.com/electron/electron/blob/master/build/fuses/fuses.json).
+You can view the current schema [here](https://github.com/electron/electron/blob/master/build/fuses/fuses.json5).

+ 2 - 0
patches/chromium/.patches

@@ -110,3 +110,5 @@ add_setter_for_browsermainloop_result_code.patch
 cherry-pick-8089dbfc616f.patch
 x11_fix_window_enumeration_order_when_wm_doesn_t_set.patch
 build_libc_as_static_library.patch
+support_runtime_configurable_key_storage_on_linux_os_crypto.patch
+make_keychain_service_account_optionally_configurable_at_runtime.patch

+ 132 - 0
patches/chromium/make_keychain_service_account_optionally_configurable_at_runtime.patch

@@ -0,0 +1,132 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Samuel Attard <[email protected]>
+Date: Fri, 7 May 2021 00:35:57 +0000
+Subject: Make keychain service/account optionally configurable at runtime
+
+This flag allows embedders to customize the service/account_name used
+for cookie crypto at runtime.  Currently these values are hardcoded
+to Chromium/Chrome and the only way to change them is to patch this
+file as part of the build process.  Making these non-const and
+assignable allows embedders to easily avoid colliding with the
+"Chrome Safe Storage" keychain value.  The const vs non-const change
+is done behind a build flag so that the normal Chrome and Chromium
+builds are unaffected.
+
+I intend to follow this up with a similar CL for changes to the
+linux crypto files too.
+
+Change-Id: Id2f9456a8dfc71a004a2dd405bed46518c559ac4
+Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2861286
+Reviewed-by: Lei Zhang <[email protected]>
+Commit-Queue: Jeremy Rose <[email protected]>
+Cr-Commit-Position: refs/heads/master@{#880168}
+
+diff --git a/components/os_crypt/BUILD.gn b/components/os_crypt/BUILD.gn
+index 79f9744a94d79e155958ee28e93eeb2b4e65d112..b9c1cf2bd914812697b161217e09ea693d2c6e65 100644
+--- a/components/os_crypt/BUILD.gn
++++ b/components/os_crypt/BUILD.gn
+@@ -51,6 +51,10 @@ component("os_crypt") {
+ 
+   defines = [ "IS_OS_CRYPT_IMPL" ]
+ 
++  if (allow_runtime_configurable_key_storage) {
++    defines += [ "ALLOW_RUNTIME_CONFIGURABLE_KEY_STORAGE" ]
++  }
++
+   if ((is_posix || is_fuchsia) && !is_apple &&
+       (!(is_linux || is_chromeos_lacros) || is_chromecast)) {
+     sources += [ "os_crypt_posix.cc" ]
+diff --git a/components/os_crypt/features.gni b/components/os_crypt/features.gni
+index a145e0530d3cdc2a04d471f98d72c3dd30e437d9..73b6e8703298b342ba94b977c9b98da0e1739bbd 100644
+--- a/components/os_crypt/features.gni
++++ b/components/os_crypt/features.gni
+@@ -9,4 +9,10 @@ declare_args() {
+   # Whether to use libgnome-keyring (deprecated by libsecret).
+   # See http://crbug.com/466975 and http://crbug.com/355223.
+   use_gnome_keyring = (is_linux || is_chromeos_lacros) && use_glib
++
++  # Whether to make account and service names for the crypto key storage
++  # configurable at runtime for embedders.
++  #
++  # Currently only has an effect on macOS via KeychainPassword
++  allow_runtime_configurable_key_storage = false
+ }
+diff --git a/components/os_crypt/keychain_password_mac.h b/components/os_crypt/keychain_password_mac.h
+index 6fda0244667c4eb5d1abb973f4b72d9c59ed2165..40b2522b87912124c106a7c28853399d31238b81 100644
+--- a/components/os_crypt/keychain_password_mac.h
++++ b/components/os_crypt/keychain_password_mac.h
+@@ -9,6 +9,7 @@
+ 
+ #include "base/component_export.h"
+ #include "base/macros.h"
++#include "base/no_destructor.h"
+ 
+ namespace crypto {
+ class AppleKeychain;
+@@ -16,6 +17,12 @@ class AppleKeychain;
+ 
+ class COMPONENT_EXPORT(OS_CRYPT) KeychainPassword {
+  public:
++#if defined(ALLOW_RUNTIME_CONFIGURABLE_KEY_STORAGE)
++  using KeychainNameType = base::NoDestructor<std::string>;
++#else
++  using KeychainNameType = const base::NoDestructor<std::string>;
++#endif
++
+   KeychainPassword(const crypto::AppleKeychain& keychain);
+   ~KeychainPassword();
+ 
+@@ -28,8 +35,8 @@ class COMPONENT_EXPORT(OS_CRYPT) KeychainPassword {
+   std::string GetPassword() const;
+ 
+   // The service and account names used in Chrome's Safe Storage keychain item.
+-  static COMPONENT_EXPORT(OS_CRYPT) const char service_name[];
+-  static COMPONENT_EXPORT(OS_CRYPT) const char account_name[];
++  static COMPONENT_EXPORT(OS_CRYPT) KeychainNameType service_name;
++  static COMPONENT_EXPORT(OS_CRYPT) KeychainNameType account_name;
+ 
+  private:
+   const crypto::AppleKeychain& keychain_;
+diff --git a/components/os_crypt/keychain_password_mac.mm b/components/os_crypt/keychain_password_mac.mm
+index 6654c46eb0af784a3a2ff64569d5d1931b9fae30..f8973f5ed0e213c0d242d2141091607017824ec3 100644
+--- a/components/os_crypt/keychain_password_mac.mm
++++ b/components/os_crypt/keychain_password_mac.mm
+@@ -48,11 +48,11 @@
+ // the encryption keyword.  So as to not lose encrypted data when system
+ // locale changes we DO NOT LOCALIZE.
+ #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+-const char KeychainPassword::service_name[] = "Chrome Safe Storage";
+-const char KeychainPassword::account_name[] = "Chrome";
++KeychainPassword::KeychainNameType KeychainPassword::service_name("Chrome Safe Storage");
++KeychainPassword::KeychainNameType KeychainPassword::account_name("Chrome");
+ #else
+-const char KeychainPassword::service_name[] = "Chromium Safe Storage";
+-const char KeychainPassword::account_name[] = "Chromium";
++KeychainPassword::KeychainNameType KeychainPassword::service_name("Chromium Safe Storage");
++KeychainPassword::KeychainNameType KeychainPassword::account_name("Chromium");
+ #endif
+ 
+ KeychainPassword::KeychainPassword(const AppleKeychain& keychain)
+@@ -64,8 +64,9 @@
+   UInt32 password_length = 0;
+   void* password_data = nullptr;
+   OSStatus error = keychain_.FindGenericPassword(
+-      strlen(service_name), service_name, strlen(account_name), account_name,
+-      &password_length, &password_data, nullptr);
++      service_name->size(), service_name->c_str(),
++      account_name->size(), account_name->c_str(), &password_length,
++      &password_data, nullptr);
+ 
+   if (error == noErr) {
+     std::string password =
+@@ -75,8 +76,8 @@
+   }
+ 
+   if (error == errSecItemNotFound) {
+-    std::string password =
+-        AddRandomPasswordToKeychain(keychain_, service_name, account_name);
++    std::string password = AddRandomPasswordToKeychain(
++        keychain_, *service_name, *account_name);
+     return password;
+   }
+ 

+ 290 - 0
patches/chromium/support_runtime_configurable_key_storage_on_linux_os_crypto.patch

@@ -0,0 +1,290 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Samuel Attard <[email protected]>
+Date: Mon, 10 May 2021 17:10:25 -0700
+Subject: support runtime configurable key storage on linux (os_crypto)
+
+This modifies the OsCrypt::Config struct used on linux to support
+runtime configurable application names which are used in the Keyring and
+LibSecret implementations of os_crypt on linux.
+
+Change-Id: Ifc287b589f118da8fcd5afaf39e5ba7ffe46f5fd
+
+diff --git a/components/os_crypt/key_storage_config_linux.h b/components/os_crypt/key_storage_config_linux.h
+index a856604756aa65c52171a9eff84ba2b316d8609c..72c16682e5df615ab84f67af66cc36c2b76c30e3 100644
+--- a/components/os_crypt/key_storage_config_linux.h
++++ b/components/os_crypt/key_storage_config_linux.h
+@@ -26,6 +26,12 @@ struct COMPONENT_EXPORT(OS_CRYPT) Config {
+   std::string store;
+   // The product name to use for permission prompts.
+   std::string product_name;
++  // The application name to store the key under. For Chromium/Chrome builds
++  // leave this unset and it will default correctly.  This config option is
++  // for embedders to provide their application name in place of "Chromium".
++  // Only used when the allow_runtime_configurable_key_storage feature is
++  // enabled.
++  std::string application_name;
+   // A runner on the main thread for gnome-keyring to be called from.
+   // TODO(crbug/466975): Libsecret and KWallet don't need this. We can remove
+   // this when we stop supporting keyring.
+diff --git a/components/os_crypt/key_storage_keyring.cc b/components/os_crypt/key_storage_keyring.cc
+index 409bd27cbc0877634d7d9809575cfa5f60ba04c2..75141308a18e5c3c083439621796f0b49b78db6b 100644
+--- a/components/os_crypt/key_storage_keyring.cc
++++ b/components/os_crypt/key_storage_keyring.cc
+@@ -15,12 +15,6 @@
+ 
+ namespace {
+ 
+-#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+-const char kApplicationName[] = "chrome";
+-#else
+-const char kApplicationName[] = "chromium";
+-#endif
+-
+ const GnomeKeyringPasswordSchema kSchema = {
+     GNOME_KEYRING_ITEM_GENERIC_SECRET,
+     {{"application", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING}, {nullptr}}};
+@@ -28,8 +22,10 @@ const GnomeKeyringPasswordSchema kSchema = {
+ }  // namespace
+ 
+ KeyStorageKeyring::KeyStorageKeyring(
+-    scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner)
+-    : main_thread_runner_(main_thread_runner) {}
++    scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner,
++    std::string application_name)
++    : main_thread_runner_(main_thread_runner),
++      application_name_(std::move(application_name)) {}
+ 
+ KeyStorageKeyring::~KeyStorageKeyring() {}
+ 
+@@ -49,7 +45,8 @@ base::Optional<std::string> KeyStorageKeyring::GetKeyImpl() {
+   gchar* password_c = nullptr;
+   GnomeKeyringResult result =
+       GnomeKeyringLoader::gnome_keyring_find_password_sync_ptr(
+-          &kSchema, &password_c, "application", kApplicationName, nullptr);
++          &kSchema, &password_c, "application", application_name_.c_str(),
++          nullptr);
+   if (result == GNOME_KEYRING_RESULT_OK) {
+     password = password_c;
+     GnomeKeyringLoader::gnome_keyring_free_password_ptr(password_c);
+@@ -71,7 +68,7 @@ base::Optional<std::string> KeyStorageKeyring::AddRandomPasswordInKeyring() {
+   GnomeKeyringResult result =
+       GnomeKeyringLoader::gnome_keyring_store_password_sync_ptr(
+           &kSchema, nullptr /* default keyring */, KeyStorageLinux::kKey,
+-          password.c_str(), "application", kApplicationName, nullptr);
++          password.c_str(), "application", application_name_.c_str(), nullptr);
+   if (result != GNOME_KEYRING_RESULT_OK) {
+     VLOG(1) << "OSCrypt failed to store generated password to gnome-keyring";
+     return base::nullopt;
+diff --git a/components/os_crypt/key_storage_keyring.h b/components/os_crypt/key_storage_keyring.h
+index 6406f2825997e0166defd7dd1457c734aa5ee6c4..fb8283f91aebe549c46deae97a483218cf4f57d7 100644
+--- a/components/os_crypt/key_storage_keyring.h
++++ b/components/os_crypt/key_storage_keyring.h
+@@ -20,8 +20,9 @@ class SingleThreadTaskRunner;
+ // Specialisation of KeyStorageLinux that uses Libsecret.
+ class COMPONENT_EXPORT(OS_CRYPT) KeyStorageKeyring : public KeyStorageLinux {
+  public:
+-  explicit KeyStorageKeyring(
+-      scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner);
++  KeyStorageKeyring(
++      scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner,
++      std::string application_name);
+   ~KeyStorageKeyring() override;
+ 
+  protected:
+@@ -37,6 +38,8 @@ class COMPONENT_EXPORT(OS_CRYPT) KeyStorageKeyring : public KeyStorageLinux {
+   // Keyring calls need to originate from the main thread.
+   scoped_refptr<base::SingleThreadTaskRunner> main_thread_runner_;
+ 
++  const std::string application_name_;
++
+   DISALLOW_COPY_AND_ASSIGN(KeyStorageKeyring);
+ };
+ 
+diff --git a/components/os_crypt/key_storage_keyring_unittest.cc b/components/os_crypt/key_storage_keyring_unittest.cc
+index 010febfe974a2bdd2efb52c78b1fc16c5d248768..0cecd45b78b871c15ed7caf1025aca8710f113f9 100644
+--- a/components/os_crypt/key_storage_keyring_unittest.cc
++++ b/components/os_crypt/key_storage_keyring_unittest.cc
+@@ -130,7 +130,7 @@ class GnomeKeyringTest : public testing::Test {
+ };
+ 
+ GnomeKeyringTest::GnomeKeyringTest()
+-    : task_runner_(new base::TestSimpleTaskRunner()), keyring_(task_runner_) {
++    : task_runner_(new base::TestSimpleTaskRunner()), keyring_(task_runner_, "chromium") {
+   MockGnomeKeyringLoader::ResetForOSCrypt();
+ }
+ 
+diff --git a/components/os_crypt/key_storage_libsecret.cc b/components/os_crypt/key_storage_libsecret.cc
+index 312570612ccb6ec4480a6f8d4a74accf5ba79ff8..f97ae381cd8e838b0150ef77d42500f66403cd11 100644
+--- a/components/os_crypt/key_storage_libsecret.cc
++++ b/components/os_crypt/key_storage_libsecret.cc
+@@ -14,12 +14,6 @@
+ 
+ namespace {
+ 
+-#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+-const char kApplicationName[] = "chrome";
+-#else
+-const char kApplicationName[] = "chromium";
+-#endif
+-
+ const SecretSchema kKeystoreSchemaV2 = {
+     "chrome_libsecret_os_crypt_password_v2",
+     SECRET_SCHEMA_DONT_MATCH_NAME,
+@@ -64,6 +58,9 @@ void AnalyseKeyHistory(GList* secret_items) {
+ 
+ }  // namespace
+ 
++KeyStorageLibsecret::KeyStorageLibsecret(std::string application_name)
++    : application_name_(std::move(application_name)) {}
++
+ base::Optional<std::string>
+ KeyStorageLibsecret::AddRandomPasswordInLibsecret() {
+   std::string password;
+@@ -71,7 +68,7 @@ KeyStorageLibsecret::AddRandomPasswordInLibsecret() {
+   GError* error = nullptr;
+   bool success = LibsecretLoader::secret_password_store_sync(
+       &kKeystoreSchemaV2, nullptr, KeyStorageLinux::kKey, password.c_str(),
+-      nullptr, &error, "application", kApplicationName, nullptr);
++      nullptr, &error, "application", application_name_.c_str(), nullptr);
+   if (error) {
+     VLOG(1) << "Libsecret lookup failed: " << error->message;
+     g_error_free(error);
+@@ -88,7 +85,7 @@ KeyStorageLibsecret::AddRandomPasswordInLibsecret() {
+ 
+ base::Optional<std::string> KeyStorageLibsecret::GetKeyImpl() {
+   LibsecretAttributesBuilder attrs;
+-  attrs.Append("application", kApplicationName);
++  attrs.Append("application", application_name_);
+ 
+   LibsecretLoader::SearchHelper helper;
+   helper.Search(&kKeystoreSchemaV2, attrs.Get(),
+diff --git a/components/os_crypt/key_storage_libsecret.h b/components/os_crypt/key_storage_libsecret.h
+index e59a2a1b5a776010556613ad63391c000ef977a4..1e889f00406cdf4eb40a3807df89432c2d57e4e1 100644
+--- a/components/os_crypt/key_storage_libsecret.h
++++ b/components/os_crypt/key_storage_libsecret.h
+@@ -15,7 +15,7 @@
+ // Specialisation of KeyStorageLinux that uses Libsecret.
+ class COMPONENT_EXPORT(OS_CRYPT) KeyStorageLibsecret : public KeyStorageLinux {
+  public:
+-  KeyStorageLibsecret() = default;
++  explicit KeyStorageLibsecret(std::string application_name);
+   ~KeyStorageLibsecret() override = default;
+ 
+  protected:
+@@ -26,6 +26,8 @@ class COMPONENT_EXPORT(OS_CRYPT) KeyStorageLibsecret : public KeyStorageLinux {
+  private:
+   base::Optional<std::string> AddRandomPasswordInLibsecret();
+ 
++  const std::string application_name_;
++
+   DISALLOW_COPY_AND_ASSIGN(KeyStorageLibsecret);
+ };
+ 
+diff --git a/components/os_crypt/key_storage_libsecret_unittest.cc b/components/os_crypt/key_storage_libsecret_unittest.cc
+index ca54c3f27b42a685dd0d695922d340f580bac57b..8988ffb928a97186f429ea96e543003a4175aacb 100644
+--- a/components/os_crypt/key_storage_libsecret_unittest.cc
++++ b/components/os_crypt/key_storage_libsecret_unittest.cc
+@@ -236,7 +236,7 @@ class LibsecretTest : public testing::Test {
+ };
+ 
+ TEST_F(LibsecretTest, LibsecretRepeats) {
+-  KeyStorageLibsecret libsecret;
++  KeyStorageLibsecret libsecret("chromium");
+   MockLibsecretLoader::ResetForOSCrypt();
+   g_password_store.Pointer()->SetPassword("initial password");
+   base::Optional<std::string> password = libsecret.GetKey();
+@@ -248,7 +248,7 @@ TEST_F(LibsecretTest, LibsecretRepeats) {
+ }
+ 
+ TEST_F(LibsecretTest, LibsecretCreatesRandomised) {
+-  KeyStorageLibsecret libsecret;
++  KeyStorageLibsecret libsecret("chromium");
+   MockLibsecretLoader::ResetForOSCrypt();
+   base::Optional<std::string> password = libsecret.GetKey();
+   MockLibsecretLoader::ResetForOSCrypt();
+diff --git a/components/os_crypt/key_storage_linux.cc b/components/os_crypt/key_storage_linux.cc
+index 33fed0fa438776e3da4de6a3589745ad8b8304e9..4f50a360fcb9cc8624de92fa2ca37a5115705271 100644
+--- a/components/os_crypt/key_storage_linux.cc
++++ b/components/os_crypt/key_storage_linux.cc
+@@ -9,6 +9,7 @@
+ #include "base/logging.h"
+ #include "base/metrics/histogram_macros.h"
+ #include "base/nix/xdg_util.h"
++#include "base/no_destructor.h"
+ #include "base/sequenced_task_runner.h"
+ #include "base/synchronization/waitable_event.h"
+ #include "base/task_runner_util.h"
+@@ -145,12 +146,29 @@ std::unique_ptr<KeyStorageLinux> KeyStorageLinux::CreateService(
+ std::unique_ptr<KeyStorageLinux> KeyStorageLinux::CreateServiceInternal(
+     os_crypt::SelectedLinuxBackend selected_backend,
+     const os_crypt::Config& config) {
++#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
++  static const base::NoDestructor<std::string> kDefaultApplicationName("chrome");
++#else
++  static const base::NoDestructor<std::string> kDefaultApplicationName("chromium");
++#endif
++
+   std::unique_ptr<KeyStorageLinux> key_storage;
+ 
++#if defined(USE_LIBSECRET) || defined(USE_KEYRING)
++#if defined(ALLOW_RUNTIME_CONFIGURABLE_KEY_STORAGE)
++  std::string application_name = config.application_name;
++  if (application_name.empty()) {
++    application_name = *kDefaultApplicationName;
++  }
++#else
++  std::string application_name = *kDefaultApplicationName;
++#endif
++#endif
++
+ #if defined(USE_LIBSECRET)
+   if (selected_backend == os_crypt::SelectedLinuxBackend::GNOME_ANY ||
+       selected_backend == os_crypt::SelectedLinuxBackend::GNOME_LIBSECRET) {
+-    key_storage.reset(new KeyStorageLibsecret());
++    key_storage.reset(new KeyStorageLibsecret(application_name));
+     if (key_storage->WaitForInitOnTaskRunner()) {
+       VLOG(1) << "OSCrypt using Libsecret as backend.";
+       return key_storage;
+@@ -162,11 +180,7 @@ std::unique_ptr<KeyStorageLinux> KeyStorageLinux::CreateServiceInternal(
+ #if defined(USE_KEYRING)
+   if (selected_backend == os_crypt::SelectedLinuxBackend::GNOME_ANY ||
+       selected_backend == os_crypt::SelectedLinuxBackend::GNOME_KEYRING) {
+-    key_storage.reset(new KeyStorageKeyring(config.main_thread_runner));
+-    if (key_storage->WaitForInitOnTaskRunner()) {
+-      VLOG(1) << "OSCrypt using Keyring as backend.";
+-      return key_storage;
+-    }
++    key_storage.reset(new KeyStorageKeyring(config.main_thread_runner, application_name));
+     LOG(WARNING) << "OSCrypt tried Keyring but couldn't initialise.";
+   }
+ #endif  // defined(USE_KEYRING)
+diff --git a/services/network/network_service.cc b/services/network/network_service.cc
+index 92d25979693ae8ecd34b9abc4afd24d274ae6921..87ef037d5c7aec1b8106051d7e3f082468e23452 100644
+--- a/services/network/network_service.cc
++++ b/services/network/network_service.cc
+@@ -621,6 +621,7 @@ void NetworkService::SetCryptConfig(mojom::CryptConfigPtr crypt_config) {
+   auto config = std::make_unique<os_crypt::Config>();
+   config->store = crypt_config->store;
+   config->product_name = crypt_config->product_name;
++  config->application_name = crypt_config->application_name;
+   config->main_thread_runner = base::ThreadTaskRunnerHandle::Get();
+   config->should_use_preference = crypt_config->should_use_preference;
+   config->user_data_path = crypt_config->user_data_path;
+diff --git a/services/network/public/mojom/network_service.mojom b/services/network/public/mojom/network_service.mojom
+index 864ca071874e54842fe418e3b84d0b8877e3e1b7..b4b12d0de2203041791cde1b1f8ef808cee23a9f 100644
+--- a/services/network/public/mojom/network_service.mojom
++++ b/services/network/public/mojom/network_service.mojom
+@@ -98,6 +98,13 @@ struct CryptConfig {
+   // The product name to use for permission prompts.
+   string product_name;
+ 
++  // The application name to store the crypto key against. For Chromium/Chrome
++  // builds leave this unset and it will default correctly.  This config option
++  // is for embedders to provide their application name in place of "Chromium".
++  // Only used when the allow_runtime_configurable_key_storage feature is
++  // enabled
++  string application_name;
++
+   // Controls whether preference on using or ignoring backends is used.
+   bool should_use_preference;
+ 

+ 26 - 3
shell/browser/browser_process_impl.cc

@@ -9,8 +9,12 @@
 #include <utility>
 
 #include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
 #include "chrome/common/chrome_switches.h"
+#include "components/os_crypt/os_crypt.h"
 #include "components/prefs/in_memory_pref_store.h"
+#include "components/prefs/json_pref_store.h"
 #include "components/prefs/overlay_user_pref_store.h"
 #include "components/prefs/pref_registry.h"
 #include "components/prefs/pref_registry_simple.h"
@@ -20,11 +24,13 @@
 #include "components/proxy_config/proxy_config_pref_names.h"
 #include "content/public/browser/child_process_security_policy.h"
 #include "content/public/common/content_switches.h"
+#include "electron/fuses.h"
 #include "extensions/common/constants.h"
 #include "net/proxy_resolution/proxy_config.h"
 #include "net/proxy_resolution/proxy_config_service.h"
 #include "net/proxy_resolution/proxy_config_with_annotation.h"
 #include "services/network/public/cpp/network_switches.h"
+#include "shell/common/electron_paths.h"
 
 #if BUILDFLAG(ENABLE_PRINTING)
 #include "chrome/browser/printing/print_job_manager.h"
@@ -83,15 +89,32 @@ BuildState* BrowserProcessImpl::GetBuildState() {
 }
 
 void BrowserProcessImpl::PostEarlyInitialization() {
-  // Mock user prefs, as we only need to track changes for a
-  // in memory pref store. There are no persistent preferences
   PrefServiceFactory prefs_factory;
   auto pref_registry = base::MakeRefCounted<PrefRegistrySimple>();
   PrefProxyConfigTrackerImpl::RegisterPrefs(pref_registry.get());
+#if defined(OS_WIN)
+  OSCrypt::RegisterLocalPrefs(pref_registry.get());
+#endif
+
   auto pref_store = base::MakeRefCounted<ValueMapPrefStore>();
   ApplyProxyModeFromCommandLine(pref_store.get());
   prefs_factory.set_command_line_prefs(std::move(pref_store));
-  prefs_factory.set_user_prefs(new OverlayUserPrefStore(new InMemoryPrefStore));
+
+  // Only use a persistent prefs store when cookie encryption is enabled as that
+  // is the only key that needs it
+  if (electron::fuses::IsCookieEncryptionEnabled()) {
+    base::FilePath prefs_path;
+    CHECK(base::PathService::Get(electron::DIR_USER_DATA, &prefs_path));
+    prefs_path = prefs_path.Append(FILE_PATH_LITERAL("Local State"));
+    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    scoped_refptr<JsonPrefStore> user_pref_store =
+        base::MakeRefCounted<JsonPrefStore>(prefs_path);
+    user_pref_store->ReadPrefs();
+    prefs_factory.set_user_prefs(user_pref_store);
+  } else {
+    prefs_factory.set_user_prefs(
+        new OverlayUserPrefStore(new InMemoryPrefStore));
+  }
   local_state_ = prefs_factory.Create(std::move(pref_registry));
 }
 

+ 12 - 0
shell/browser/electron_browser_main_parts.cc

@@ -17,6 +17,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/icon_manager.h"
+#include "components/os_crypt/os_crypt.h"
 #include "content/browser/browser_main_loop.h"  // nogncheck
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/child_process_security_policy.h"
@@ -26,6 +27,7 @@
 #include "content/public/common/content_switches.h"
 #include "content/public/common/result_codes.h"
 #include "electron/buildflags/buildflags.h"
+#include "electron/fuses.h"
 #include "media/base/localized_strings.h"
 #include "services/network/public/cpp/features.h"
 #include "services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler.h"
@@ -549,6 +551,16 @@ void ElectronBrowserMainParts::PreMainMessageLoopStartCommon() {
   RegisterURLHandler();
 #endif
   media::SetLocalizedStringProvider(MediaStringProvider);
+
+#if defined(OS_WIN)
+  if (electron::fuses::IsCookieEncryptionEnabled()) {
+    auto* local_state = g_browser_process->local_state();
+    DCHECK(local_state);
+
+    bool os_crypt_init = OSCrypt::Init(local_state);
+    DCHECK(os_crypt_init);
+  }
+#endif
 }
 
 device::mojom::GeolocationControl*

+ 3 - 3
shell/browser/net/network_context_service.cc

@@ -9,6 +9,7 @@
 #include "chrome/common/chrome_constants.h"
 #include "content/public/browser/network_service_instance.h"
 #include "content/public/browser/shared_cors_origin_access_list.h"
+#include "electron/fuses.h"
 #include "net/net_buildflags.h"
 #include "services/network/network_service.h"
 #include "services/network/public/cpp/cors/origin_access_list.h"
@@ -77,9 +78,8 @@ void NetworkContextService::ConfigureNetworkContextParams(
     network_context_params->restore_old_session_cookies = false;
     network_context_params->persist_session_cookies = false;
 
-    // TODO(deepak1556): Matches the existing behavior https://git.io/fxHMl,
-    // enable encryption as a followup.
-    network_context_params->enable_encrypted_cookies = false;
+    network_context_params->enable_encrypted_cookies =
+        electron::fuses::IsCookieEncryptionEnabled();
 
     network_context_params->transport_security_persister_path = path;
   }

+ 44 - 0
shell/browser/net/system_network_context_manager.cc

@@ -8,11 +8,16 @@
 #include <utility>
 
 #include "base/command_line.h"
+#include "base/path_service.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/net/chrome_mojo_proxy_resolver_factory.h"
+#include "chrome/common/chrome_switches.h"
+#include "components/os_crypt/os_crypt.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/network_service_instance.h"
 #include "content/public/common/content_features.h"
+#include "content/public/common/network_service_util.h"
+#include "electron/fuses.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "net/net_buildflags.h"
 #include "services/cert_verifier/public/mojom/cert_verifier_service_factory.mojom.h"
@@ -21,11 +26,17 @@
 #include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/mojom/network_context.mojom.h"
+#include "shell/browser/browser.h"
 #include "shell/browser/electron_browser_client.h"
 #include "shell/common/application_info.h"
+#include "shell/common/electron_paths.h"
 #include "shell/common/options_switches.h"
 #include "url/gurl.h"
 
+#if defined(OS_MAC)
+#include "components/os_crypt/keychain_password_mac.h"
+#endif
+
 namespace {
 
 // The global instance of the SystemNetworkContextmanager.
@@ -218,6 +229,39 @@ void SystemNetworkContextManager::OnNetworkServiceCreated(
   network_service->CreateNetworkContext(
       network_context_.BindNewPipeAndPassReceiver(),
       CreateNetworkContextParams());
+
+  if (electron::fuses::IsCookieEncryptionEnabled()) {
+    std::string app_name = electron::Browser::Get()->GetName();
+#if defined(OS_MAC)
+    *KeychainPassword::service_name = app_name + " Safe Storage";
+    *KeychainPassword::account_name = app_name;
+#endif
+    // The OSCrypt keys are process bound, so if network service is out of
+    // process, send it the required key.
+    if (content::IsOutOfProcessNetworkService()) {
+#if defined(OS_LINUX)
+      // c.f.
+      // https://source.chromium.org/chromium/chromium/src/+/master:chrome/browser/net/system_network_context_manager.cc;l=515;drc=9d82515060b9b75fa941986f5db7390299669ef1;bpv=1;bpt=1
+      const base::CommandLine& command_line =
+          *base::CommandLine::ForCurrentProcess();
+
+      network::mojom::CryptConfigPtr config =
+          network::mojom::CryptConfig::New();
+      config->application_name = app_name;
+      config->product_name = app_name;
+      // c.f.
+      // https://source.chromium.org/chromium/chromium/src/+/master:chrome/common/chrome_switches.cc;l=689;drc=9d82515060b9b75fa941986f5db7390299669ef1
+      config->store =
+          command_line.GetSwitchValueASCII(::switches::kPasswordStore);
+      config->should_use_preference =
+          command_line.HasSwitch(::switches::kEnableEncryptionSelection);
+      base::PathService::Get(electron::DIR_USER_DATA, &config->user_data_path);
+      network_service->SetCryptConfig(std::move(config));
+#else
+      network_service->SetEncryptionKey(OSCrypt::GetRawEncryptionKey());
+#endif
+    }
+  }
 }
 
 network::mojom::NetworkContextParamsPtr