From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samuel Attard <samuel.r.attard@gmail.com>
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;
 
