blob: a1b5b975bc89c4891643adab17ce0b00ba2a8032 [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"
8#include "base/rand_util.h"
9#include "base/strings/string_number_conversions.h"
10#include "components/os_crypt/libsecret_util_linux.h"
11
12namespace {
13
cfroussios02da78d2016-08-30 09:27:0514#if defined(GOOGLE_CHROME_BUILD)
15const char kApplicationName[] = "chrome";
16#else
17const char kApplicationName[] = "chromium";
18#endif
19
20// Deprecated in M55 (crbug.com/639298)
21const SecretSchema kKeystoreSchemaV1 = {
cfroussios3b5a4e42016-05-31 11:02:1822 "chrome_libsecret_os_crypt_password",
23 SECRET_SCHEMA_NONE,
24 {
25 {nullptr, SECRET_SCHEMA_ATTRIBUTE_STRING},
26 }};
27
cfroussios02da78d2016-08-30 09:27:0528const SecretSchema kKeystoreSchemaV2 = {
29 "chrome_libsecret_os_crypt_password_v2",
30 SECRET_SCHEMA_DONT_MATCH_NAME,
31 {
32 {"application", SECRET_SCHEMA_ATTRIBUTE_STRING},
33 {nullptr, SECRET_SCHEMA_ATTRIBUTE_STRING},
34 }};
35
cfroussios51e9b142016-10-24 14:28:3136// From a search result, extracts a SecretValue, asserting that there was at
37// most one result. Returns nullptr if there are no results.
38SecretValue* ToSingleSecret(GList* secret_items) {
39 GList* first = g_list_first(secret_items);
40 if (first == nullptr)
41 return nullptr;
42 if (g_list_next(first) != nullptr) {
43 VLOG(1) << "OSCrypt found more than one encryption keys.";
44 }
45 SecretItem* secret_item = static_cast<SecretItem*>(first->data);
46 SecretValue* secret_value =
47 LibsecretLoader::secret_item_get_secret(secret_item);
cfroussios51e9b142016-10-24 14:28:3148 return secret_value;
49}
50
cfroussios2e6729a42016-07-26 09:18:1251} // namespace
52
53std::string KeyStorageLibsecret::AddRandomPasswordInLibsecret() {
cfroussios3b5a4e42016-05-31 11:02:1854 std::string password;
55 base::Base64Encode(base::RandBytesAsString(16), &password);
56 GError* error = nullptr;
cfroussios02da78d2016-08-30 09:27:0557 bool success = LibsecretLoader::secret_password_store_sync(
58 &kKeystoreSchemaV2, nullptr, KeyStorageLinux::kKey, password.c_str(),
59 nullptr, &error, "application", kApplicationName, nullptr);
cfroussios51e9b142016-10-24 14:28:3160 if (error) {
cfroussios3b5a4e42016-05-31 11:02:1861 VLOG(1) << "Libsecret lookup failed: " << error->message;
cfroussios51e9b142016-10-24 14:28:3162 g_error_free(error);
63 return std::string();
64 }
65 if (!success) {
66 VLOG(1) << "Libsecret lookup failed.";
cfroussios3b5a4e42016-05-31 11:02:1867 return std::string();
68 }
cfroussios02da78d2016-08-30 09:27:0569
70 VLOG(1) << "OSCrypt generated a new password.";
cfroussios3b5a4e42016-05-31 11:02:1871 return password;
72}
73
Christos Froussios985d1aac2017-11-09 11:01:0774std::string KeyStorageLibsecret::GetKeyImpl() {
cfroussios3b5a4e42016-05-31 11:02:1875 LibsecretAttributesBuilder attrs;
cfroussios02da78d2016-08-30 09:27:0576 attrs.Append("application", kApplicationName);
erikchene3e1bc72018-01-18 16:31:2977
78 LibsecretLoader::SearchHelper helper;
79 helper.Search(&kKeystoreSchemaV2, attrs.Get(),
80 SECRET_SEARCH_UNLOCK | SECRET_SEARCH_LOAD_SECRETS);
81 if (!helper.success()) {
82 VLOG(1) << "Libsecret lookup failed: " << helper.error()->message;
cfroussios3b5a4e42016-05-31 11:02:1883 return std::string();
84 }
erikchene3e1bc72018-01-18 16:31:2985
86 SecretValue* password_libsecret = ToSingleSecret(helper.results());
cfroussios3b5a4e42016-05-31 11:02:1887 if (!password_libsecret) {
cfroussios02da78d2016-08-30 09:27:0588 std::string password = Migrate();
89 if (!password.empty())
90 return password;
cfroussios3b5a4e42016-05-31 11:02:1891 return AddRandomPasswordInLibsecret();
92 }
93 std::string password(
94 LibsecretLoader::secret_value_get_text(password_libsecret));
95 LibsecretLoader::secret_value_unref(password_libsecret);
96 return password;
97}
98
99bool KeyStorageLibsecret::Init() {
cfroussiosf3a8dfe2016-10-28 15:30:32100 bool loaded = LibsecretLoader::EnsureLibsecretLoaded();
101 if (loaded)
102 LibsecretLoader::EnsureKeyringUnlocked();
103 return loaded;
cfroussios3b5a4e42016-05-31 11:02:18104}
cfroussios02da78d2016-08-30 09:27:05105
106std::string KeyStorageLibsecret::Migrate() {
cfroussios02da78d2016-08-30 09:27:05107 LibsecretAttributesBuilder attrs;
108
109 // Detect old entry.
erikchene3e1bc72018-01-18 16:31:29110 LibsecretLoader::SearchHelper helper;
111 helper.Search(&kKeystoreSchemaV1, attrs.Get(),
112 SECRET_SEARCH_UNLOCK | SECRET_SEARCH_LOAD_SECRETS);
113 if (!helper.success())
cfroussios51e9b142016-10-24 14:28:31114 return std::string();
erikchene3e1bc72018-01-18 16:31:29115
116 SecretValue* password_libsecret = ToSingleSecret(helper.results());
cfroussios51e9b142016-10-24 14:28:31117 if (!password_libsecret)
cfroussios02da78d2016-08-30 09:27:05118 return std::string();
119
120 VLOG(1) << "OSCrypt detected a deprecated password in Libsecret.";
121 std::string password(
122 LibsecretLoader::secret_value_get_text(password_libsecret));
cfroussios51e9b142016-10-24 14:28:31123 LibsecretLoader::secret_value_unref(password_libsecret);
cfroussios02da78d2016-08-30 09:27:05124
125 // Create new entry.
erikchene3e1bc72018-01-18 16:31:29126 GError* error = nullptr;
cfroussios02da78d2016-08-30 09:27:05127 bool success = LibsecretLoader::secret_password_store_sync(
128 &kKeystoreSchemaV2, nullptr, KeyStorageLinux::kKey, password.c_str(),
129 nullptr, &error, "application", kApplicationName, nullptr);
cfroussios51e9b142016-10-24 14:28:31130 if (error) {
131 VLOG(1) << "Failed to store migrated password. " << error->message;
132 g_error_free(error);
cfroussios02da78d2016-08-30 09:27:05133 return std::string();
cfroussios51e9b142016-10-24 14:28:31134 }
135 if (!success) {
136 VLOG(1) << "Failed to store migrated password.";
137 return std::string();
138 }
cfroussios02da78d2016-08-30 09:27:05139
140 // Delete old entry.
141 // Even if deletion failed, we have to use the password that we created.
142 success = LibsecretLoader::secret_password_clear_sync(
143 &kKeystoreSchemaV1, nullptr, &error, nullptr);
cfroussios51e9b142016-10-24 14:28:31144 if (error) {
145 VLOG(1) << "OSCrypt failed to delete deprecated password. "
146 << error->message;
147 g_error_free(error);
148 }
cfroussios02da78d2016-08-30 09:27:05149
150 VLOG(1) << "OSCrypt migrated from deprecated password.";
151
152 return password;
153}