blob: b8a3d7c0da2f95b04aba98d70e630272a10c96ad [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"
Nico Weber356b3042019-08-23 15:30:4110#include "build/branding_buildflags.h"
cfroussios3b5a4e42016-05-31 11:02:1811#include "components/os_crypt/libsecret_util_linux.h"
12
13namespace {
14
Nico Weber356b3042019-08-23 15:30:4115#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
cfroussios02da78d2016-08-30 09:27:0516const char kApplicationName[] = "chrome";
17#else
18const char kApplicationName[] = "chromium";
19#endif
20
21// Deprecated in M55 (crbug.com/639298)
22const SecretSchema kKeystoreSchemaV1 = {
cfroussios3b5a4e42016-05-31 11:02:1823 "chrome_libsecret_os_crypt_password",
24 SECRET_SCHEMA_NONE,
25 {
26 {nullptr, SECRET_SCHEMA_ATTRIBUTE_STRING},
27 }};
28
cfroussios02da78d2016-08-30 09:27:0529const SecretSchema kKeystoreSchemaV2 = {
30 "chrome_libsecret_os_crypt_password_v2",
31 SECRET_SCHEMA_DONT_MATCH_NAME,
32 {
33 {"application", SECRET_SCHEMA_ATTRIBUTE_STRING},
34 {nullptr, SECRET_SCHEMA_ATTRIBUTE_STRING},
35 }};
36
cfroussios51e9b142016-10-24 14:28:3137// From a search result, extracts a SecretValue, asserting that there was at
38// most one result. Returns nullptr if there are no results.
39SecretValue* ToSingleSecret(GList* secret_items) {
40 GList* first = g_list_first(secret_items);
41 if (first == nullptr)
42 return nullptr;
43 if (g_list_next(first) != nullptr) {
44 VLOG(1) << "OSCrypt found more than one encryption keys.";
45 }
46 SecretItem* secret_item = static_cast<SecretItem*>(first->data);
47 SecretValue* secret_value =
48 LibsecretLoader::secret_item_get_secret(secret_item);
cfroussios51e9b142016-10-24 14:28:3149 return secret_value;
50}
51
cfroussios2e6729a42016-07-26 09:18:1252} // namespace
53
54std::string KeyStorageLibsecret::AddRandomPasswordInLibsecret() {
cfroussios3b5a4e42016-05-31 11:02:1855 std::string password;
56 base::Base64Encode(base::RandBytesAsString(16), &password);
57 GError* error = nullptr;
cfroussios02da78d2016-08-30 09:27:0558 bool success = LibsecretLoader::secret_password_store_sync(
59 &kKeystoreSchemaV2, nullptr, KeyStorageLinux::kKey, password.c_str(),
60 nullptr, &error, "application", kApplicationName, nullptr);
cfroussios51e9b142016-10-24 14:28:3161 if (error) {
cfroussios3b5a4e42016-05-31 11:02:1862 VLOG(1) << "Libsecret lookup failed: " << error->message;
cfroussios51e9b142016-10-24 14:28:3163 g_error_free(error);
64 return std::string();
65 }
66 if (!success) {
67 VLOG(1) << "Libsecret lookup failed.";
cfroussios3b5a4e42016-05-31 11:02:1868 return std::string();
69 }
cfroussios02da78d2016-08-30 09:27:0570
71 VLOG(1) << "OSCrypt generated a new password.";
cfroussios3b5a4e42016-05-31 11:02:1872 return password;
73}
74
Christos Froussios985d1aac2017-11-09 11:01:0775std::string KeyStorageLibsecret::GetKeyImpl() {
cfroussios3b5a4e42016-05-31 11:02:1876 LibsecretAttributesBuilder attrs;
cfroussios02da78d2016-08-30 09:27:0577 attrs.Append("application", kApplicationName);
erikchene3e1bc72018-01-18 16:31:2978
79 LibsecretLoader::SearchHelper helper;
80 helper.Search(&kKeystoreSchemaV2, attrs.Get(),
81 SECRET_SEARCH_UNLOCK | SECRET_SEARCH_LOAD_SECRETS);
82 if (!helper.success()) {
83 VLOG(1) << "Libsecret lookup failed: " << helper.error()->message;
cfroussios3b5a4e42016-05-31 11:02:1884 return std::string();
85 }
erikchene3e1bc72018-01-18 16:31:2986
87 SecretValue* password_libsecret = ToSingleSecret(helper.results());
cfroussios3b5a4e42016-05-31 11:02:1888 if (!password_libsecret) {
cfroussios02da78d2016-08-30 09:27:0589 std::string password = Migrate();
90 if (!password.empty())
91 return password;
cfroussios3b5a4e42016-05-31 11:02:1892 return AddRandomPasswordInLibsecret();
93 }
94 std::string password(
95 LibsecretLoader::secret_value_get_text(password_libsecret));
96 LibsecretLoader::secret_value_unref(password_libsecret);
97 return password;
98}
99
100bool KeyStorageLibsecret::Init() {
cfroussiosf3a8dfe2016-10-28 15:30:32101 bool loaded = LibsecretLoader::EnsureLibsecretLoaded();
102 if (loaded)
103 LibsecretLoader::EnsureKeyringUnlocked();
104 return loaded;
cfroussios3b5a4e42016-05-31 11:02:18105}
cfroussios02da78d2016-08-30 09:27:05106
107std::string KeyStorageLibsecret::Migrate() {
cfroussios02da78d2016-08-30 09:27:05108 LibsecretAttributesBuilder attrs;
109
110 // Detect old entry.
erikchene3e1bc72018-01-18 16:31:29111 LibsecretLoader::SearchHelper helper;
112 helper.Search(&kKeystoreSchemaV1, attrs.Get(),
113 SECRET_SEARCH_UNLOCK | SECRET_SEARCH_LOAD_SECRETS);
114 if (!helper.success())
cfroussios51e9b142016-10-24 14:28:31115 return std::string();
erikchene3e1bc72018-01-18 16:31:29116
117 SecretValue* password_libsecret = ToSingleSecret(helper.results());
cfroussios51e9b142016-10-24 14:28:31118 if (!password_libsecret)
cfroussios02da78d2016-08-30 09:27:05119 return std::string();
120
121 VLOG(1) << "OSCrypt detected a deprecated password in Libsecret.";
122 std::string password(
123 LibsecretLoader::secret_value_get_text(password_libsecret));
cfroussios51e9b142016-10-24 14:28:31124 LibsecretLoader::secret_value_unref(password_libsecret);
cfroussios02da78d2016-08-30 09:27:05125
126 // Create new entry.
erikchene3e1bc72018-01-18 16:31:29127 GError* error = nullptr;
cfroussios02da78d2016-08-30 09:27:05128 bool success = LibsecretLoader::secret_password_store_sync(
129 &kKeystoreSchemaV2, nullptr, KeyStorageLinux::kKey, password.c_str(),
130 nullptr, &error, "application", kApplicationName, nullptr);
cfroussios51e9b142016-10-24 14:28:31131 if (error) {
132 VLOG(1) << "Failed to store migrated password. " << error->message;
133 g_error_free(error);
cfroussios02da78d2016-08-30 09:27:05134 return std::string();
cfroussios51e9b142016-10-24 14:28:31135 }
136 if (!success) {
137 VLOG(1) << "Failed to store migrated password.";
138 return std::string();
139 }
cfroussios02da78d2016-08-30 09:27:05140
141 // Delete old entry.
142 // Even if deletion failed, we have to use the password that we created.
143 success = LibsecretLoader::secret_password_clear_sync(
144 &kKeystoreSchemaV1, nullptr, &error, nullptr);
cfroussios51e9b142016-10-24 14:28:31145 if (error) {
146 VLOG(1) << "OSCrypt failed to delete deprecated password. "
147 << error->message;
148 g_error_free(error);
149 }
cfroussios02da78d2016-08-30 09:27:05150
151 VLOG(1) << "OSCrypt migrated from deprecated password.";
152
153 return password;
154}