blob: c16d6a2c64fa347458a8c4656ada5c3eb1978b27 [file] [log] [blame]
cfroussios3b5a4e42016-05-31 11:02:181// 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
5#include "components/os_crypt/key_storage_linux.h"
6
Christos Froussios4e170cb2017-12-01 09:42:337#include "base/bind.h"
cfroussios3ea4c692016-07-18 19:15:148#include "base/environment.h"
cfroussios3ea4c692016-07-18 19:15:149#include "base/logging.h"
10#include "base/nix/xdg_util.h"
Christos Froussios4e170cb2017-12-01 09:42:3311#include "base/sequenced_task_runner.h"
12#include "base/synchronization/waitable_event.h"
13#include "base/task_runner_util.h"
14#include "base/threading/thread_restrictions.h"
Nico Weber356b3042019-08-23 15:30:4115#include "build/branding_buildflags.h"
Christos Froussios494196d2017-07-14 10:10:0416#include "components/os_crypt/key_storage_config_linux.h"
cfroussios2f05d7f2016-08-17 15:58:5017#include "components/os_crypt/key_storage_util_linux.h"
cfroussios3ea4c692016-07-18 19:15:1418
19#if defined(USE_LIBSECRET)
cfroussios3b5a4e42016-05-31 11:02:1820#include "components/os_crypt/key_storage_libsecret.h"
cfroussios3ea4c692016-07-18 19:15:1421#endif
cfroussiosb013c15b2016-09-03 01:10:1622#if defined(USE_KEYRING)
23#include "components/os_crypt/key_storage_keyring.h"
24#endif
cfroussios2e6729a42016-07-26 09:18:1225#if defined(USE_KWALLET)
26#include "components/os_crypt/key_storage_kwallet.h"
27#endif
28
Nico Weber356b3042019-08-23 15:30:4129#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
cfroussios2e6729a42016-07-26 09:18:1230const char KeyStorageLinux::kFolderName[] = "Chrome Keys";
31const char KeyStorageLinux::kKey[] = "Chrome Safe Storage";
32#else
33const char KeyStorageLinux::kFolderName[] = "Chromium Keys";
34const char KeyStorageLinux::kKey[] = "Chromium Safe Storage";
35#endif
36
Christos Froussiosf7924a62019-11-05 14:26:5037namespace {
38
39const char* SelectedLinuxBackendToString(
40 os_crypt::SelectedLinuxBackend selection) {
41 switch (selection) {
42 case os_crypt::SelectedLinuxBackend::DEFER:
43 return "DEFER";
44 case os_crypt::SelectedLinuxBackend::BASIC_TEXT:
45 return "BASIC_TEXT";
46 case os_crypt::SelectedLinuxBackend::GNOME_ANY:
47 return "GNOME_ANY";
48 case os_crypt::SelectedLinuxBackend::GNOME_KEYRING:
49 return "GNOME_KEYRING";
50 case os_crypt::SelectedLinuxBackend::GNOME_LIBSECRET:
51 return "GNOME_LIBSECRET";
52 case os_crypt::SelectedLinuxBackend::KWALLET:
53 return "KWALLET";
54 case os_crypt::SelectedLinuxBackend::KWALLET5:
55 return "KWALLET5";
56 }
57 NOTREACHED();
58 return nullptr;
59}
60
61} // namespace
62
cfroussios3ea4c692016-07-18 19:15:1463// static
Christos Froussios494196d2017-07-14 10:10:0464std::unique_ptr<KeyStorageLinux> KeyStorageLinux::CreateService(
65 const os_crypt::Config& config) {
slana881a862016-09-09 21:36:0766#if defined(USE_LIBSECRET) || defined(USE_KEYRING) || defined(USE_KWALLET)
cfroussios2f05d7f2016-08-17 15:58:5067 // Select a backend.
Christos Froussios494196d2017-07-14 10:10:0468 bool use_backend = !config.should_use_preference ||
69 os_crypt::GetBackendUse(config.user_data_path);
cfroussios2f05d7f2016-08-17 15:58:5070 std::unique_ptr<base::Environment> env(base::Environment::Create());
71 base::nix::DesktopEnvironment desktop_env =
72 base::nix::GetDesktopEnvironment(env.get());
73 os_crypt::SelectedLinuxBackend selected_backend =
Christos Froussios494196d2017-07-14 10:10:0474 os_crypt::SelectBackend(config.store, use_backend, desktop_env);
Christos Froussiosf7924a62019-11-05 14:26:5075 VLOG(1) << "Selected backend for OSCrypt: "
76 << SelectedLinuxBackendToString(selected_backend);
cfroussios3b5a4e42016-05-31 11:02:1877
Christos Froussios985d1aac2017-11-09 11:01:0778 // TODO(crbug.com/782851) Schedule the initialisation on each backend's
79 // favourite thread.
80
cfroussios2f05d7f2016-08-17 15:58:5081 // Try initializing the selected backend.
cfroussiosb013c15b2016-09-03 01:10:1682 // In case of GNOME_ANY, prefer Libsecret
cfroussios3ea4c692016-07-18 19:15:1483 std::unique_ptr<KeyStorageLinux> key_storage;
cfroussiosb013c15b2016-09-03 01:10:1684
85#if defined(USE_LIBSECRET)
cfroussios2f05d7f2016-08-17 15:58:5086 if (selected_backend == os_crypt::SelectedLinuxBackend::GNOME_ANY ||
87 selected_backend == os_crypt::SelectedLinuxBackend::GNOME_LIBSECRET) {
Christos Froussios70cc95b2017-12-14 21:13:2388 key_storage.reset(new KeyStorageLibsecret());
Christos Froussios4e170cb2017-12-01 09:42:3389 if (key_storage->WaitForInitOnTaskRunner()) {
cfroussios3ea4c692016-07-18 19:15:1490 VLOG(1) << "OSCrypt using Libsecret as backend.";
91 return key_storage;
92 }
Christos Froussiosf7924a62019-11-05 14:26:5093 LOG(WARNING) << "OSCrypt tried Libsecret but couldn't initialise.";
cfroussiosb013c15b2016-09-03 01:10:1694 }
slana881a862016-09-09 21:36:0795#endif // defined(USE_LIBSECRET)
cfroussiosb013c15b2016-09-03 01:10:1696
97#if defined(USE_KEYRING)
98 if (selected_backend == os_crypt::SelectedLinuxBackend::GNOME_ANY ||
99 selected_backend == os_crypt::SelectedLinuxBackend::GNOME_KEYRING) {
Christos Froussios70cc95b2017-12-14 21:13:23100 key_storage.reset(new KeyStorageKeyring(config.main_thread_runner));
Christos Froussios4e170cb2017-12-01 09:42:33101 if (key_storage->WaitForInitOnTaskRunner()) {
cfroussiosb013c15b2016-09-03 01:10:16102 VLOG(1) << "OSCrypt using Keyring as backend.";
103 return key_storage;
104 }
Christos Froussiosf7924a62019-11-05 14:26:50105 LOG(WARNING) << "OSCrypt tried Keyring but couldn't initialise.";
cfroussiosb013c15b2016-09-03 01:10:16106 }
slana881a862016-09-09 21:36:07107#endif // defined(USE_KEYRING)
cfroussiosb013c15b2016-09-03 01:10:16108
cfroussios2e6729a42016-07-26 09:18:12109#if defined(USE_KWALLET)
cfroussiosb013c15b2016-09-03 01:10:16110 if (selected_backend == os_crypt::SelectedLinuxBackend::KWALLET ||
111 selected_backend == os_crypt::SelectedLinuxBackend::KWALLET5) {
Christos Froussios494196d2017-07-14 10:10:04112 DCHECK(!config.product_name.empty());
cfroussios2f05d7f2016-08-17 15:58:50113 base::nix::DesktopEnvironment used_desktop_env =
114 selected_backend == os_crypt::SelectedLinuxBackend::KWALLET
115 ? base::nix::DESKTOP_ENVIRONMENT_KDE4
116 : base::nix::DESKTOP_ENVIRONMENT_KDE5;
Christos Froussios70cc95b2017-12-14 21:13:23117 key_storage.reset(
118 new KeyStorageKWallet(used_desktop_env, config.product_name));
Christos Froussios4e170cb2017-12-01 09:42:33119 if (key_storage->WaitForInitOnTaskRunner()) {
cfroussios2e6729a42016-07-26 09:18:12120 VLOG(1) << "OSCrypt using KWallet as backend.";
121 return key_storage;
122 }
Christos Froussiosf7924a62019-11-05 14:26:50123 LOG(WARNING) << "OSCrypt tried KWallet but couldn't initialise.";
cfroussios3ea4c692016-07-18 19:15:14124 }
slana881a862016-09-09 21:36:07125#endif // defined(USE_KWALLET)
126#endif // defined(USE_LIBSECRET) || defined(USE_KEYRING) ||
127 // defined(USE_KWALLET)
cfroussios3b5a4e42016-05-31 11:02:18128
Christos Froussiosf7924a62019-11-05 14:26:50129 // Either there are no supported backends on this platform, or we chose to
130 // use no backend, or the chosen backend failed to initialise.
cfroussios6b340f812017-07-06 15:05:10131 VLOG(1) << "OSCrypt did not initialize a backend.";
cfroussios3b5a4e42016-05-31 11:02:18132 return nullptr;
133}
Christos Froussios985d1aac2017-11-09 11:01:07134
Christos Froussios4e170cb2017-12-01 09:42:33135bool KeyStorageLinux::WaitForInitOnTaskRunner() {
136 base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_sync_primitives;
137 base::SequencedTaskRunner* task_runner = GetTaskRunner();
138
139 // We don't need to change threads if the backend has no preference or if we
140 // are already on the right thread.
141 if (!task_runner || task_runner->RunsTasksInCurrentSequence())
142 return Init();
143
144 base::WaitableEvent initialized(
145 base::WaitableEvent::ResetPolicy::MANUAL,
146 base::WaitableEvent::InitialState::NOT_SIGNALED);
147 bool success;
Christos Froussios57fe5742017-12-07 21:16:49148 task_runner->PostTask(
149 FROM_HERE,
150 base::BindOnce(&KeyStorageLinux::BlockOnInitThenSignal,
151 base::Unretained(this), &initialized, &success));
Christos Froussios4e170cb2017-12-01 09:42:33152 initialized.Wait();
153 return success;
154}
155
Christos Froussios985d1aac2017-11-09 11:01:07156std::string KeyStorageLinux::GetKey() {
Christos Froussios4e170cb2017-12-01 09:42:33157 base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_sync_primitives;
158 base::SequencedTaskRunner* task_runner = GetTaskRunner();
159
160 // We don't need to change threads if the backend has no preference or if we
161 // are already on the right thread.
162 if (!task_runner || task_runner->RunsTasksInCurrentSequence())
163 return GetKeyImpl();
164
165 base::WaitableEvent password_loaded(
166 base::WaitableEvent::ResetPolicy::MANUAL,
167 base::WaitableEvent::InitialState::NOT_SIGNALED);
168 std::string password;
Christos Froussios57fe5742017-12-07 21:16:49169 task_runner->PostTask(
170 FROM_HERE,
171 base::BindOnce(&KeyStorageLinux::BlockOnGetKeyImplThenSignal,
172 base::Unretained(this), &password_loaded, &password));
Christos Froussios4e170cb2017-12-01 09:42:33173 password_loaded.Wait();
174 return password;
175}
176
177base::SequencedTaskRunner* KeyStorageLinux::GetTaskRunner() {
178 return nullptr;
Christos Froussios985d1aac2017-11-09 11:01:07179}
Christos Froussios57fe5742017-12-07 21:16:49180
181void KeyStorageLinux::BlockOnGetKeyImplThenSignal(
182 base::WaitableEvent* on_password_received,
183 std::string* password) {
184 *password = GetKeyImpl();
185 on_password_received->Signal();
186}
187
188void KeyStorageLinux::BlockOnInitThenSignal(base::WaitableEvent* on_inited,
189 bool* success) {
190 *success = Init();
191 on_inited->Signal();
192}