Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(77)

Side by Side Diff: chrome/browser/chromeos/login/quick_unlock/pin_backend.cc

Issue 2809993004: cros: Implement cryptohome backend for pin.
Patch Set: Rebase, remove some extraneous LOG statements Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 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 "chrome/browser/chromeos/login/quick_unlock/pin_backend.h"
6
7 #include "base/bind.h"
8 #include "base/threading/thread_task_runner_handle.h"
9 #include "chrome/browser/chromeos/login/quick_unlock/pin_storage_prefs.h"
10 #include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_factory.h"
11 #include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_storage.h"
12 #include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.h"
13 #include "chromeos/cryptohome/cryptohome_parameters.h"
14 #include "chromeos/cryptohome/homedir_methods.h"
15 #include "chromeos/cryptohome/system_salt_getter.h"
16 #include "chromeos/login/auth/user_context.h"
17 #include "components/signin/core/account_id/account_id.h"
18
19 namespace chromeos {
20 namespace quick_unlock {
21
22 namespace {
23
24 constexpr const char* kCryptohomePinLabel = "pin_label";
25
26 void DoNothingCryptohome(bool success, cryptohome::MountError return_code) {}
27
28 class CryptohomeBackend {
29 public:
30 CryptohomeBackend();
31 ~CryptohomeBackend();
32
33 void EnsurePinIsNotInCryptohome(const AccountId& account_id,
34 const UserContext& user_context) const;
35 void IsPinSetInCryptohome(const AccountId& account_id,
36 const PinBackend::BoolCallback& result) const;
37 void SetPin(const UserContext& user_context, const std::string& pin);
38 void RemovePin(const UserContext& user_context);
39 bool NeedsStrongAuth() const;
40
41 private:
42 void OnSystemSaltObtained(const std::string& system_salt);
43 // Called when we add or remove a key from cryptohome.
44 void OnCryptohomeKeyChange(bool success, cryptohome::MountError return_code);
45
46 void SetIsPinSet(bool is_set);
47
48 private:
49 bool salt_obtained_ = false;
50 std::string system_salt_;
51 std::vector<base::Closure> system_salt_callbacks_;
52
53 base::WeakPtrFactory<CryptohomeBackend> weak_factory_;
achuithb 2017/05/13 01:01:58 You can do weak_factory_{this}; https://cs.chromiu
jdufault 2017/06/06 18:17:06 Done - that's a nice pattern.
54
55 DISALLOW_COPY_AND_ASSIGN(CryptohomeBackend);
56 };
57
58 CryptohomeBackend::CryptohomeBackend() : weak_factory_(this) {
59 SystemSaltGetter::Get()->GetSystemSalt(base::Bind(
60 &CryptohomeBackend::OnSystemSaltObtained, weak_factory_.GetWeakPtr()));
61 }
62
63 CryptohomeBackend::~CryptohomeBackend() {}
64
65 void CryptohomeBackend::IsPinSetInCryptohome(
66 const AccountId& account_id,
67 const PinBackend::BoolCallback& callback) const {
68 auto on_key_data =
achuithb 2017/05/13 01:01:58 Let's maybe pull this out into a named callback? I
jdufault 2017/06/06 18:17:06 Done.
69 [](const PinBackend::BoolCallback& callback, bool success,
70 cryptohome::MountError return_code,
71 const std::vector<cryptohome::KeyDefinition>& key_definitions) {
72
73 for (const cryptohome::KeyDefinition& definition : key_definitions) {
74 if (definition.label == kCryptohomePinLabel) {
75 callback.Run(true);
76 return;
77 }
78 }
79
80 callback.Run(false);
81 };
82
83 cryptohome::HomedirMethods::GetInstance()->GetKeyDataEx(
84 cryptohome::Identification(account_id), kCryptohomePinLabel,
85 base::Bind(on_key_data, callback));
86 }
87
88 void CryptohomeBackend::SetPin(const UserContext& user_context,
89 const std::string& pin) {
90 // Rerun this method only after we have system salt.
91 if (!salt_obtained_) {
92 system_salt_callbacks_.push_back(base::Bind(&CryptohomeBackend::SetPin,
93 weak_factory_.GetWeakPtr(),
94 user_context, pin));
95 return;
96 }
97
98 const std::string pin_secret = PinBackend::ComputeSecret(pin, system_salt_);
99
100 cryptohome::Identification id(user_context.GetAccountId());
achuithb 2017/05/13 01:01:58 nit all const
jdufault 2017/06/06 18:17:06 Done.
101 cryptohome::Authorization auth(user_context.GetKey()->GetSecret(), "");
102 cryptohome::KeyDefinition key_def(pin_secret, kCryptohomePinLabel,
103 cryptohome::PRIV_DEFAULT);
104 cryptohome::HomedirMethods::GetInstance()->AddKeyEx(
105 id, auth, key_def, true /*replace_existing*/,
106 base::Bind(&DoNothingCryptohome));
107 }
108
109 void CryptohomeBackend::OnSystemSaltObtained(const std::string& system_salt) {
110 salt_obtained_ = true;
111 system_salt_ = system_salt;
112 for (std::vector<base::Closure>::const_iterator it =
achuithb 2017/05/13 01:01:58 Does range-based loop not work here?
jdufault 2017/06/06 18:17:06 Done - not sure why I wasn't using it.
113 system_salt_callbacks_.begin();
114 it != system_salt_callbacks_.end(); ++it) {
115 it->Run();
116 }
117 system_salt_callbacks_.clear();
118 }
119
120 void CryptohomeBackend::RemovePin(const UserContext& user_context) {
121 // Rerun this method only after we have system salt.
122 if (!salt_obtained_) {
123 system_salt_callbacks_.push_back(base::Bind(&CryptohomeBackend::RemovePin,
124 weak_factory_.GetWeakPtr(),
125 user_context));
126 return;
127 }
128
129 // Remove any PIN data from cryptohome.
130 cryptohome::Identification id(user_context.GetAccountId());
achuithb 2017/05/13 01:01:58 nit const
jdufault 2017/06/06 18:17:06 Done.
131 cryptohome::Authorization auth(user_context.GetKey()->GetSecret(), "");
132 cryptohome::HomedirMethods::GetInstance()->RemoveKeyEx(
133 id, auth, kCryptohomePinLabel, base::Bind(&DoNothingCryptohome));
134 }
135
136 CryptohomeBackend* g_cryptohome_backend_ = nullptr;
137
138 CryptohomeBackend* GetCryptohomeBackend() {
139 if (!g_cryptohome_backend_)
140 g_cryptohome_backend_ = new CryptohomeBackend();
141 return g_cryptohome_backend_;
achuithb 2017/05/13 01:01:58 it's ok to leak this? Isn't there a singleton cl
jdufault 2017/06/06 18:17:06 I tried converting to a leaky base::Singleton inst
142 }
143
144 QuickUnlockStorage* GetPrefsBackend(const AccountId& account_id) {
145 return QuickUnlockFactory::GetForAccountId(account_id);
146 }
147
148 void SendResponse(const PinBackend::BoolCallback& result, bool value) {
149 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
150 base::Bind(result, value));
151 }
152
153 } // namespace
154
155 // static
156 void PinBackend::IsSet(const AccountId& account_id,
157 const BoolCallback& result) {
158 if (GetPinStorageType() == PinStorageType::kCryptohome) {
159 GetCryptohomeBackend()->IsPinSetInCryptohome(account_id, result);
160 } else {
161 QuickUnlockStorage* storage = GetPrefsBackend(account_id);
162 DCHECK(storage);
163 SendResponse(result, storage->pin_storage_prefs()->IsPinSet());
164 }
165 }
166
167 // static
168 void PinBackend::Set(const UserContext& user_context, const std::string& pin) {
169 QuickUnlockStorage* storage = GetPrefsBackend(user_context.GetAccountId());
170 DCHECK(storage);
171
172 // Make sure to remove the other storage pin.
173 if (GetPinStorageType() == PinStorageType::kCryptohome) {
174 GetCryptohomeBackend()->SetPin(user_context, pin);
175 storage->pin_storage_prefs()->RemovePin();
176 } else {
177 storage->pin_storage_prefs()->SetPin(pin);
178 GetCryptohomeBackend()->RemovePin(user_context);
179 }
180 }
181
182 // static
183 void PinBackend::Remove(const UserContext& user_context) {
184 GetCryptohomeBackend()->RemovePin(user_context);
185
186 QuickUnlockStorage* storage = GetPrefsBackend(user_context.GetAccountId());
187 DCHECK(storage);
188 storage->pin_storage_prefs()->RemovePin();
189 }
190
191 // static
192 void PinBackend::CanAuthenticate(const AccountId& account_id,
193 const BoolCallback& result) {
194 if (GetPinStorageType() == PinStorageType::kCryptohome) {
195 GetCryptohomeBackend()->IsPinSetInCryptohome(account_id, result);
196 } else {
197 QuickUnlockStorage* storage = GetPrefsBackend(account_id);
198 if (!storage) {
199 SendResponse(result, false);
200 } else {
201 SendResponse(
202 result,
203 storage->HasStrongAuth() &&
204 storage->pin_storage_prefs()->IsPinAuthenticationAvailable());
205 }
206 }
207 }
208
209 // static
210 void PinBackend::TryAuthenticate(const AccountId& account_id,
211 const std::string& pin,
212 const BoolCallback& result) {
213 if (GetPinStorageType() == PinStorageType::kCryptohome) {
214 // TODO(jdufalt): Refactor login auth such that typing a user password does
215 // not run crypthome check with wildcard key label. That means we will be
216 // forced to run an authentication check here.
217 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
218 base::Bind(result, false));
219 } else {
220 QuickUnlockStorage* storage = GetPrefsBackend(account_id);
221 DCHECK(storage);
222
223 if (!storage->HasStrongAuth()) {
224 SendResponse(result, false);
225 } else {
226 SendResponse(result,
227 storage->pin_storage_prefs()->TryAuthenticatePin(pin));
228 }
229 }
230 }
231
232 // static
233 void PinBackend::NotifyAuthentication(const AccountId& account_id) {
234 // Nothing to do for cryptohome backend.
235
236 if (GetPinStorageType() == PinStorageType::kPrefs) {
237 QuickUnlockStorage* storage = GetPrefsBackend(account_id);
238 if (!storage)
239 return;
240
241 storage->pin_storage_prefs()->ResetUnlockAttemptCount();
242 }
243 }
244
245 // static
246 std::string PinBackend::ComputeSecret(const std::string& pin,
247 const std::string& salt) {
248 Key key(pin);
249 key.Transform(Key::KEY_TYPE_SALTED_SHA256_TOP_HALF, salt);
250 return key.GetSecret();
251 }
252
253 // static
254 void PinBackend::ResetForTesting() {
255 if (g_cryptohome_backend_)
256 delete g_cryptohome_backend_;
257 g_cryptohome_backend_ = nullptr;
258 }
259
260 } // namespace quick_unlock
261 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698