key_storage_linux.cc 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. // Copyright 2016 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/os_crypt/key_storage_linux.h"
  5. #include <memory>
  6. #include "base/bind.h"
  7. #include "base/environment.h"
  8. #include "base/logging.h"
  9. #include "base/metrics/histogram_macros.h"
  10. #include "base/nix/xdg_util.h"
  11. #include "base/no_destructor.h"
  12. #include "base/synchronization/waitable_event.h"
  13. #include "base/task/sequenced_task_runner.h"
  14. #include "base/task/task_runner_util.h"
  15. #include "base/threading/thread_restrictions.h"
  16. #include "build/branding_buildflags.h"
  17. #include "components/os_crypt/key_storage_config_linux.h"
  18. #if defined(USE_LIBSECRET)
  19. #include "components/os_crypt/key_storage_libsecret.h"
  20. #endif
  21. #if defined(USE_KEYRING)
  22. #include "components/os_crypt/key_storage_keyring.h"
  23. #endif
  24. #if defined(USE_KWALLET)
  25. #include "components/os_crypt/key_storage_kwallet.h"
  26. #endif
  27. #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
  28. const char KeyStorageLinux::kFolderName[] = "Chrome Keys";
  29. const char KeyStorageLinux::kKey[] = "Chrome Safe Storage";
  30. #else
  31. const char KeyStorageLinux::kFolderName[] = "Chromium Keys";
  32. const char KeyStorageLinux::kKey[] = "Chromium Safe Storage";
  33. #endif
  34. namespace {
  35. // Used for metrics. Do not rearrange.
  36. enum class BackendUsage {
  37. // A backend was selected and used.
  38. // *_FAILED means the backend was selected but couldn't be used.
  39. kDefer = 0,
  40. kDeferFailed = 1,
  41. kBasicText = 2,
  42. kBasicTextFailed = 3,
  43. kGnomeAny = 4,
  44. kGnomeAnyFailed = 5,
  45. kGnomeKeyring = 6,
  46. kGnomeKeyringFailed = 7,
  47. kGnomeLibsecret = 8,
  48. kGnomeLibsecretFailed = 9,
  49. kKwallet = 10,
  50. kKwalletFailed = 11,
  51. kKwallet5 = 12,
  52. kKwallet5Failed = 13,
  53. kMaxValue = kKwallet5Failed,
  54. };
  55. constexpr BackendUsage SelectedBackendToMetric(
  56. os_crypt::SelectedLinuxBackend selection,
  57. bool used) {
  58. switch (selection) {
  59. case os_crypt::SelectedLinuxBackend::DEFER:
  60. return used ? BackendUsage::kDefer : BackendUsage::kDeferFailed;
  61. case os_crypt::SelectedLinuxBackend::BASIC_TEXT:
  62. return used ? BackendUsage::kBasicText : BackendUsage::kBasicTextFailed;
  63. case os_crypt::SelectedLinuxBackend::GNOME_ANY:
  64. return used ? BackendUsage::kGnomeAny : BackendUsage::kGnomeAnyFailed;
  65. case os_crypt::SelectedLinuxBackend::GNOME_KEYRING:
  66. return used ? BackendUsage::kGnomeKeyring
  67. : BackendUsage::kGnomeKeyringFailed;
  68. case os_crypt::SelectedLinuxBackend::GNOME_LIBSECRET:
  69. return used ? BackendUsage::kGnomeLibsecret
  70. : BackendUsage::kGnomeLibsecretFailed;
  71. case os_crypt::SelectedLinuxBackend::KWALLET:
  72. return used ? BackendUsage::kKwallet : BackendUsage::kKwalletFailed;
  73. case os_crypt::SelectedLinuxBackend::KWALLET5:
  74. return used ? BackendUsage::kKwallet5 : BackendUsage::kKwallet5Failed;
  75. }
  76. NOTREACHED();
  77. return BackendUsage::kDeferFailed;
  78. }
  79. const char* SelectedLinuxBackendToString(
  80. os_crypt::SelectedLinuxBackend selection) {
  81. switch (selection) {
  82. case os_crypt::SelectedLinuxBackend::DEFER:
  83. return "DEFER";
  84. case os_crypt::SelectedLinuxBackend::BASIC_TEXT:
  85. return "BASIC_TEXT";
  86. case os_crypt::SelectedLinuxBackend::GNOME_ANY:
  87. return "GNOME_ANY";
  88. case os_crypt::SelectedLinuxBackend::GNOME_KEYRING:
  89. return "GNOME_KEYRING";
  90. case os_crypt::SelectedLinuxBackend::GNOME_LIBSECRET:
  91. return "GNOME_LIBSECRET";
  92. case os_crypt::SelectedLinuxBackend::KWALLET:
  93. return "KWALLET";
  94. case os_crypt::SelectedLinuxBackend::KWALLET5:
  95. return "KWALLET5";
  96. }
  97. NOTREACHED();
  98. return nullptr;
  99. }
  100. } // namespace
  101. // static
  102. std::unique_ptr<KeyStorageLinux> KeyStorageLinux::CreateService(
  103. const os_crypt::Config& config) {
  104. // Select a backend.
  105. bool use_backend = !config.should_use_preference ||
  106. os_crypt::GetBackendUse(config.user_data_path);
  107. std::unique_ptr<base::Environment> env(base::Environment::Create());
  108. base::nix::DesktopEnvironment desktop_env =
  109. base::nix::GetDesktopEnvironment(env.get());
  110. os_crypt::SelectedLinuxBackend selected_backend =
  111. os_crypt::SelectBackend(config.store, use_backend, desktop_env);
  112. VLOG(1) << "Selected backend for OSCrypt: "
  113. << SelectedLinuxBackendToString(selected_backend);
  114. // TODO(crbug.com/782851) Schedule the initialisation on each backend's
  115. // favourite thread.
  116. // Try initializing the selected backend.
  117. // In case of GNOME_ANY, prefer Libsecret
  118. std::unique_ptr<KeyStorageLinux> key_storage;
  119. #if defined(USE_LIBSECRET) || defined(USE_KEYRING) || defined(USE_KWALLET)
  120. key_storage = CreateServiceInternal(selected_backend, config);
  121. #endif // defined(USE_LIBSECRET) || defined(USE_KEYRING) ||
  122. // defined(USE_KWALLET)
  123. UMA_HISTOGRAM_ENUMERATION(
  124. "OSCrypt.BackendUsage",
  125. SelectedBackendToMetric(selected_backend, key_storage != nullptr));
  126. // Either there are no supported backends on this platform, or we chose to
  127. // use no backend, or the chosen backend failed to initialise.
  128. VLOG_IF(1, !key_storage) << "OSCrypt did not initialize a backend.";
  129. return key_storage;
  130. }
  131. #if defined(USE_LIBSECRET) || defined(USE_KEYRING) || defined(USE_KWALLET)
  132. std::unique_ptr<KeyStorageLinux> KeyStorageLinux::CreateServiceInternal(
  133. os_crypt::SelectedLinuxBackend selected_backend,
  134. const os_crypt::Config& config) {
  135. #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
  136. static const base::NoDestructor<std::string> kDefaultApplicationName("chrome");
  137. #else
  138. static const base::NoDestructor<std::string> kDefaultApplicationName("chromium");
  139. #endif
  140. std::unique_ptr<KeyStorageLinux> key_storage;
  141. #if defined(USE_LIBSECRET) || defined(USE_KEYRING)
  142. #if defined(ALLOW_RUNTIME_CONFIGURABLE_KEY_STORAGE)
  143. std::string application_name = config.application_name;
  144. if (application_name.empty()) {
  145. application_name = *kDefaultApplicationName;
  146. }
  147. #else
  148. std::string application_name = *kDefaultApplicationName;
  149. #endif
  150. #endif
  151. #if defined(USE_LIBSECRET)
  152. if (selected_backend == os_crypt::SelectedLinuxBackend::GNOME_ANY ||
  153. selected_backend == os_crypt::SelectedLinuxBackend::GNOME_LIBSECRET) {
  154. key_storage = std::make_unique<KeyStorageLibsecret>(application_name);
  155. if (key_storage->WaitForInitOnTaskRunner()) {
  156. VLOG(1) << "OSCrypt using Libsecret as backend.";
  157. return key_storage;
  158. }
  159. LOG(WARNING) << "OSCrypt tried Libsecret but couldn't initialise.";
  160. }
  161. #endif // defined(USE_LIBSECRET)
  162. #if defined(USE_KEYRING)
  163. if (selected_backend == os_crypt::SelectedLinuxBackend::GNOME_ANY ||
  164. selected_backend == os_crypt::SelectedLinuxBackend::GNOME_KEYRING) {
  165. key_storage = std::make_unique<KeyStorageKeyring>(config.main_thread_runner,
  166. application_name);
  167. if (key_storage->WaitForInitOnTaskRunner()) {
  168. VLOG(1) << "OSCrypt using Keyring as backend.";
  169. return key_storage;
  170. }
  171. LOG(WARNING) << "OSCrypt tried Keyring but couldn't initialise.";
  172. }
  173. #endif // defined(USE_KEYRING)
  174. #if defined(USE_KWALLET)
  175. if (selected_backend == os_crypt::SelectedLinuxBackend::KWALLET ||
  176. selected_backend == os_crypt::SelectedLinuxBackend::KWALLET5) {
  177. DCHECK(!config.product_name.empty());
  178. base::nix::DesktopEnvironment used_desktop_env =
  179. selected_backend == os_crypt::SelectedLinuxBackend::KWALLET
  180. ? base::nix::DESKTOP_ENVIRONMENT_KDE4
  181. : base::nix::DESKTOP_ENVIRONMENT_KDE5;
  182. key_storage = std::make_unique<KeyStorageKWallet>(used_desktop_env,
  183. config.product_name);
  184. if (key_storage->WaitForInitOnTaskRunner()) {
  185. VLOG(1) << "OSCrypt using KWallet as backend.";
  186. return key_storage;
  187. }
  188. LOG(WARNING) << "OSCrypt tried KWallet but couldn't initialise.";
  189. }
  190. #endif // defined(USE_KWALLET)
  191. return nullptr;
  192. }
  193. #endif // defined(USE_LIBSECRET) || defined(USE_KEYRING) ||
  194. // defined(USE_KWALLET)
  195. bool KeyStorageLinux::WaitForInitOnTaskRunner() {
  196. base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_sync_primitives;
  197. base::SequencedTaskRunner* task_runner = GetTaskRunner();
  198. // We don't need to change threads if the backend has no preference or if we
  199. // are already on the right thread.
  200. if (!task_runner || task_runner->RunsTasksInCurrentSequence())
  201. return Init();
  202. base::WaitableEvent initialized(
  203. base::WaitableEvent::ResetPolicy::MANUAL,
  204. base::WaitableEvent::InitialState::NOT_SIGNALED);
  205. bool success;
  206. task_runner->PostTask(
  207. FROM_HERE,
  208. base::BindOnce(&KeyStorageLinux::BlockOnInitThenSignal,
  209. base::Unretained(this), &initialized, &success));
  210. initialized.Wait();
  211. return success;
  212. }
  213. absl::optional<std::string> KeyStorageLinux::GetKey() {
  214. base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_sync_primitives;
  215. base::SequencedTaskRunner* task_runner = GetTaskRunner();
  216. // We don't need to change threads if the backend has no preference or if we
  217. // are already on the right thread.
  218. if (!task_runner || task_runner->RunsTasksInCurrentSequence())
  219. return GetKeyImpl();
  220. base::WaitableEvent password_loaded(
  221. base::WaitableEvent::ResetPolicy::MANUAL,
  222. base::WaitableEvent::InitialState::NOT_SIGNALED);
  223. absl::optional<std::string> password;
  224. task_runner->PostTask(
  225. FROM_HERE,
  226. base::BindOnce(&KeyStorageLinux::BlockOnGetKeyImplThenSignal,
  227. base::Unretained(this), &password_loaded, &password));
  228. password_loaded.Wait();
  229. return password;
  230. }
  231. base::SequencedTaskRunner* KeyStorageLinux::GetTaskRunner() {
  232. return nullptr;
  233. }
  234. void KeyStorageLinux::BlockOnGetKeyImplThenSignal(
  235. base::WaitableEvent* on_password_received,
  236. absl::optional<std::string>* password) {
  237. *password = GetKeyImpl();
  238. on_password_received->Signal();
  239. }
  240. void KeyStorageLinux::BlockOnInitThenSignal(base::WaitableEvent* on_inited,
  241. bool* success) {
  242. *success = Init();
  243. on_inited->Signal();
  244. }