blob: 0857cc1874f4153541c7f21dd8cc6bdc1d59b39d [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_libsecret.h"
6
7#include "base/base64.h"
Hans Wennborg628c19e2020-04-21 13:14:468#include "base/logging.h"
cfroussios3b5a4e42016-05-31 11:02:189#include "base/rand_util.h"
10#include "base/strings/string_number_conversions.h"
Christos Froussiosb655ab892019-12-18 13:53:0311#include "base/time/time.h"
Nico Weber356b3042019-08-23 15:30:4112#include "build/branding_buildflags.h"
cfroussios3b5a4e42016-05-31 11:02:1813#include "components/os_crypt/libsecret_util_linux.h"
14
15namespace {
16
Nico Weber356b3042019-08-23 15:30:4117#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
cfroussios02da78d2016-08-30 09:27:0518const char kApplicationName[] = "chrome";
19#else
20const char kApplicationName[] = "chromium";
21#endif
22
cfroussios02da78d2016-08-30 09:27:0523const SecretSchema kKeystoreSchemaV2 = {
24 "chrome_libsecret_os_crypt_password_v2",
25 SECRET_SCHEMA_DONT_MATCH_NAME,
26 {
27 {"application", SECRET_SCHEMA_ATTRIBUTE_STRING},
28 {nullptr, SECRET_SCHEMA_ATTRIBUTE_STRING},
29 }};
30
cfroussios51e9b142016-10-24 14:28:3131// From a search result, extracts a SecretValue, asserting that there was at
32// most one result. Returns nullptr if there are no results.
33SecretValue* ToSingleSecret(GList* secret_items) {
34 GList* first = g_list_first(secret_items);
35 if (first == nullptr)
36 return nullptr;
37 if (g_list_next(first) != nullptr) {
38 VLOG(1) << "OSCrypt found more than one encryption keys.";
39 }
40 SecretItem* secret_item = static_cast<SecretItem*>(first->data);
41 SecretValue* secret_value =
42 LibsecretLoader::secret_item_get_secret(secret_item);
cfroussios51e9b142016-10-24 14:28:3143 return secret_value;
44}
45
Christos Froussiosb655ab892019-12-18 13:53:0346// Checks the timestamps of the secret item and prints findings to logs. We
47// presume that at most one secret item can be present.
48void AnalyseKeyHistory(GList* secret_items) {
49 GList* first = g_list_first(secret_items);
50 if (first == nullptr)
51 return;
52
53 SecretItem* secret_item = static_cast<SecretItem*>(first->data);
54 auto created = base::Time::FromTimeT(
55 LibsecretLoader::secret_item_get_created(secret_item));
56 auto last_modified = base::Time::FromTimeT(
57 LibsecretLoader::secret_item_get_modified(secret_item));
58
59 VLOG(1) << "Libsecret key created: " << created;
60 VLOG(1) << "Libsecret key last modified: " << last_modified;
61 LOG_IF(WARNING, created != last_modified)
62 << "the encryption key has been modified since it was created.";
63}
64
cfroussios2e6729a42016-07-26 09:18:1265} // namespace
66
Anton Bikineev1156b5f2021-05-15 22:35:3667absl::optional<std::string>
Anton Bershanskiy9fa2a352020-05-06 11:38:5368KeyStorageLibsecret::AddRandomPasswordInLibsecret() {
cfroussios3b5a4e42016-05-31 11:02:1869 std::string password;
70 base::Base64Encode(base::RandBytesAsString(16), &password);
71 GError* error = nullptr;
cfroussios02da78d2016-08-30 09:27:0572 bool success = LibsecretLoader::secret_password_store_sync(
73 &kKeystoreSchemaV2, nullptr, KeyStorageLinux::kKey, password.c_str(),
74 nullptr, &error, "application", kApplicationName, nullptr);
cfroussios51e9b142016-10-24 14:28:3175 if (error) {
cfroussios3b5a4e42016-05-31 11:02:1876 VLOG(1) << "Libsecret lookup failed: " << error->message;
cfroussios51e9b142016-10-24 14:28:3177 g_error_free(error);
Anton Bikineev1156b5f2021-05-15 22:35:3678 return absl::nullopt;
cfroussios51e9b142016-10-24 14:28:3179 }
80 if (!success) {
81 VLOG(1) << "Libsecret lookup failed.";
Anton Bikineev1156b5f2021-05-15 22:35:3682 return absl::nullopt;
cfroussios3b5a4e42016-05-31 11:02:1883 }
cfroussios02da78d2016-08-30 09:27:0584
85 VLOG(1) << "OSCrypt generated a new password.";
cfroussios3b5a4e42016-05-31 11:02:1886 return password;
87}
88
Anton Bikineev1156b5f2021-05-15 22:35:3689absl::optional<std::string> KeyStorageLibsecret::GetKeyImpl() {
cfroussios3b5a4e42016-05-31 11:02:1890 LibsecretAttributesBuilder attrs;
cfroussios02da78d2016-08-30 09:27:0591 attrs.Append("application", kApplicationName);
erikchene3e1bc72018-01-18 16:31:2992
93 LibsecretLoader::SearchHelper helper;
94 helper.Search(&kKeystoreSchemaV2, attrs.Get(),
95 SECRET_SEARCH_UNLOCK | SECRET_SEARCH_LOAD_SECRETS);
96 if (!helper.success()) {
97 VLOG(1) << "Libsecret lookup failed: " << helper.error()->message;
Anton Bikineev1156b5f2021-05-15 22:35:3698 return absl::nullopt;
cfroussios3b5a4e42016-05-31 11:02:1899 }
erikchene3e1bc72018-01-18 16:31:29100
101 SecretValue* password_libsecret = ToSingleSecret(helper.results());
cfroussios3b5a4e42016-05-31 11:02:18102 if (!password_libsecret) {
cfroussios3b5a4e42016-05-31 11:02:18103 return AddRandomPasswordInLibsecret();
104 }
Christos Froussiosb655ab892019-12-18 13:53:03105 AnalyseKeyHistory(helper.results());
Anton Bikineev1156b5f2021-05-15 22:35:36106 absl::optional<std::string> password(
cfroussios3b5a4e42016-05-31 11:02:18107 LibsecretLoader::secret_value_get_text(password_libsecret));
108 LibsecretLoader::secret_value_unref(password_libsecret);
109 return password;
110}
111
112bool KeyStorageLibsecret::Init() {
cfroussiosf3a8dfe2016-10-28 15:30:32113 bool loaded = LibsecretLoader::EnsureLibsecretLoaded();
114 if (loaded)
115 LibsecretLoader::EnsureKeyringUnlocked();
116 return loaded;
cfroussios3b5a4e42016-05-31 11:02:18117}