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

Side by Side Diff: components/sync/driver/sync_service_crypto.cc

Issue 2663783002: [Sync] Split encryption state and logic out of PSS and SBHI. (Closed)
Patch Set: Tweak comment. Created 3 years, 10 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
« no previous file with comments | « components/sync/driver/sync_service_crypto.h ('k') | components/sync/engine/fake_sync_engine.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 "components/sync/driver/sync_service_crypto.h"
6
7 #include <utility>
8
9 #include "base/feature_list.h"
10 #include "base/memory/ptr_util.h"
11 #include "base/metrics/histogram_macros.h"
12 #include "base/sequenced_task_runner.h"
13 #include "base/threading/thread_task_runner_handle.h"
14 #include "components/sync/base/nigori.h"
15 #include "components/sync/base/sync_prefs.h"
16 #include "components/sync/driver/data_type_manager.h"
17 #include "components/sync/driver/sync_driver_switches.h"
18 #include "components/sync/driver/sync_service.h"
19 #include "components/sync/engine/sync_string_conversions.h"
20
21 namespace syncer {
22
23 namespace {
24
25 // A SyncEncryptionHandler::Observer implementation that simply posts all calls
26 // to another task runner.
27 class SyncEncryptionObserverProxy : public SyncEncryptionHandler::Observer {
28 public:
29 SyncEncryptionObserverProxy(
30 base::WeakPtr<SyncEncryptionHandler::Observer> observer,
31 scoped_refptr<base::SequencedTaskRunner> task_runner)
32 : observer_(observer), task_runner_(std::move(task_runner)) {}
33
34 void OnPassphraseRequired(
35 PassphraseRequiredReason reason,
36 const sync_pb::EncryptedData& pending_keys) override {
37 task_runner_->PostTask(
38 FROM_HERE,
39 base::Bind(&SyncEncryptionHandler::Observer::OnPassphraseRequired,
40 observer_, reason, pending_keys));
41 }
42
43 void OnPassphraseAccepted() override {
44 task_runner_->PostTask(
45 FROM_HERE,
46 base::Bind(&SyncEncryptionHandler::Observer::OnPassphraseAccepted,
47 observer_));
48 }
49
50 void OnBootstrapTokenUpdated(const std::string& bootstrap_token,
51 BootstrapTokenType type) override {
52 task_runner_->PostTask(
53 FROM_HERE,
54 base::Bind(&SyncEncryptionHandler::Observer::OnBootstrapTokenUpdated,
55 observer_, bootstrap_token, type));
56 }
57
58 void OnEncryptedTypesChanged(ModelTypeSet encrypted_types,
59 bool encrypt_everything) override {
60 task_runner_->PostTask(
61 FROM_HERE,
62 base::Bind(&SyncEncryptionHandler::Observer::OnEncryptedTypesChanged,
63 observer_, encrypted_types, encrypt_everything));
64 }
65
66 void OnEncryptionComplete() override {
67 task_runner_->PostTask(
68 FROM_HERE,
69 base::Bind(&SyncEncryptionHandler::Observer::OnEncryptionComplete,
70 observer_));
71 }
72
73 void OnCryptographerStateChanged(Cryptographer* cryptographer) override {
74 task_runner_->PostTask(
75 FROM_HERE,
76 base::Bind(
77 &SyncEncryptionHandler::Observer::OnCryptographerStateChanged,
78 observer_, cryptographer));
79 }
80
81 void OnPassphraseTypeChanged(PassphraseType type,
82 base::Time passphrase_time) override {
83 task_runner_->PostTask(
84 FROM_HERE,
85 base::Bind(&SyncEncryptionHandler::Observer::OnPassphraseTypeChanged,
86 observer_, type, passphrase_time));
87 }
88
89 void OnLocalSetPassphraseEncryption(
90 const SyncEncryptionHandler::NigoriState& nigori_state) override {
91 task_runner_->PostTask(
92 FROM_HERE,
93 base::Bind(
94 &SyncEncryptionHandler::Observer::OnLocalSetPassphraseEncryption,
95 observer_, nigori_state));
96 }
97
98 private:
99 base::WeakPtr<SyncEncryptionHandler::Observer> observer_;
100 scoped_refptr<base::SequencedTaskRunner> task_runner_;
101 };
102
103 } // namespace
104
105 SyncServiceCrypto::SyncServiceCrypto(
106 const base::Closure& notify_observers,
107 const base::Callback<ModelTypeSet()>& get_preferred_types,
108 SyncPrefs* sync_prefs)
109 : notify_observers_(notify_observers),
110 get_preferred_types_(get_preferred_types),
111 sync_prefs_(sync_prefs),
112 weak_factory_(this) {
113 DCHECK(notify_observers_);
114 DCHECK(get_preferred_types_);
115 DCHECK(sync_prefs_);
116 }
117
118 SyncServiceCrypto::~SyncServiceCrypto() = default;
119
120 base::Time SyncServiceCrypto::GetExplicitPassphraseTime() const {
121 DCHECK(thread_checker_.CalledOnValidThread());
122 return cached_explicit_passphrase_time_;
123 }
124
125 bool SyncServiceCrypto::IsUsingSecondaryPassphrase() const {
126 DCHECK(thread_checker_.CalledOnValidThread());
127 return cached_passphrase_type_ ==
128 PassphraseType::FROZEN_IMPLICIT_PASSPHRASE ||
129 cached_passphrase_type_ == PassphraseType::CUSTOM_PASSPHRASE;
130 }
131
132 void SyncServiceCrypto::EnableEncryptEverything() {
133 DCHECK(thread_checker_.CalledOnValidThread());
134 DCHECK(IsEncryptEverythingAllowed());
135 DCHECK(engine_);
136
137 // TODO(atwilson): Persist the encryption_pending_ flag to address the various
138 // problems around cancelling encryption in the background (crbug.com/119649).
139 if (!encrypt_everything_)
140 encryption_pending_ = true;
141 }
142
143 bool SyncServiceCrypto::IsEncryptEverythingEnabled() const {
144 DCHECK(thread_checker_.CalledOnValidThread());
145 DCHECK(engine_);
146 return encrypt_everything_ || encryption_pending_;
147 }
148
149 void SyncServiceCrypto::SetEncryptionPassphrase(const std::string& passphrase,
150 bool is_explicit) {
151 DCHECK(thread_checker_.CalledOnValidThread());
152 // This should only be called when the engine has been initialized.
153 DCHECK(engine_);
154 DCHECK(data_type_manager_);
155 DCHECK(!(!is_explicit && IsUsingSecondaryPassphrase()))
156 << "Data is already encrypted using an explicit passphrase";
157 DCHECK(!(is_explicit && passphrase_required_reason_ == REASON_DECRYPTION))
158 << "Can not set explicit passphrase when decryption is needed.";
159
160 DVLOG(1) << "Setting " << (is_explicit ? "explicit" : "implicit")
161 << " passphrase for encryption.";
162 if (passphrase_required_reason_ == REASON_ENCRYPTION) {
163 // REASON_ENCRYPTION implies that the cryptographer does not have pending
164 // keys. Hence, as long as we're not trying to do an invalid passphrase
165 // change (e.g. explicit -> explicit or explicit -> implicit), we know this
166 // will succeed. If for some reason a new encryption key arrives via
167 // sync later, the SBH will trigger another OnPassphraseRequired().
168 passphrase_required_reason_ = REASON_PASSPHRASE_NOT_REQUIRED;
169 notify_observers_.Run();
170 }
171
172 if (!data_type_manager_->IsNigoriEnabled()) {
173 NOTREACHED() << "SetEncryptionPassphrase must never be called when nigori"
174 " is disabled.";
175 return;
176 }
177
178 // We should never be called with an empty passphrase.
179 DCHECK(!passphrase.empty());
180
181 // SetEncryptionPassphrase should never be called if we are currently
182 // encrypted with an explicit passphrase.
183 DCHECK(cached_passphrase_type_ == PassphraseType::KEYSTORE_PASSPHRASE ||
184 cached_passphrase_type_ == PassphraseType::IMPLICIT_PASSPHRASE);
185
186 engine_->SetEncryptionPassphrase(passphrase, is_explicit);
187 }
188
189 bool SyncServiceCrypto::SetDecryptionPassphrase(const std::string& passphrase) {
190 DCHECK(thread_checker_.CalledOnValidThread());
191 DCHECK(data_type_manager_);
192
193 if (!data_type_manager_->IsNigoriEnabled()) {
194 NOTREACHED() << "SetDecryptionPassphrase must never be called when nigori"
195 " is disabled.";
196 return false;
197 }
198
199 // We should never be called with an empty passphrase.
200 DCHECK(!passphrase.empty());
201
202 // This should only be called when we have cached pending keys.
203 DCHECK(cached_pending_keys_.has_blob());
204
205 // Check the passphrase that was provided against our local cache of the
206 // cryptographer's pending keys. If this was unsuccessful, the UI layer can
207 // immediately call OnPassphraseRequired without showing the user a spinner.
208 if (!CheckPassphraseAgainstCachedPendingKeys(passphrase))
209 return false;
210
211 engine_->SetDecryptionPassphrase(passphrase);
212
213 // Since we were able to decrypt the cached pending keys with the passphrase
214 // provided, we immediately alert the UI layer that the passphrase was
215 // accepted. This will avoid the situation where a user enters a passphrase,
216 // clicks OK, immediately reopens the advanced settings dialog, and gets an
217 // unnecessary prompt for a passphrase.
218 // Note: It is not guaranteed that the passphrase will be accepted by the
219 // syncer thread, since we could receive a new nigori node while the task is
220 // pending. This scenario is a valid race, and SetDecryptionPassphrase can
221 // trigger a new OnPassphraseRequired if it needs to.
222 OnPassphraseAccepted();
223 return true;
224 }
225
226 PassphraseType SyncServiceCrypto::GetPassphraseType() const {
227 DCHECK(thread_checker_.CalledOnValidThread());
228 return cached_passphrase_type_;
229 }
230
231 bool SyncServiceCrypto::IsEncryptEverythingAllowed() const {
232 DCHECK(thread_checker_.CalledOnValidThread());
233 return encrypt_everything_allowed_;
234 }
235
236 void SyncServiceCrypto::SetEncryptEverythingAllowed(bool allowed) {
237 DCHECK(thread_checker_.CalledOnValidThread());
238 DCHECK(allowed || !engine_ || !IsEncryptEverythingEnabled());
239 encrypt_everything_allowed_ = allowed;
240 }
241
242 ModelTypeSet SyncServiceCrypto::GetEncryptedDataTypes() const {
243 DCHECK(thread_checker_.CalledOnValidThread());
244 DCHECK(encrypted_types_.Has(PASSWORDS));
245 // We may be called during the setup process before we're
246 // initialized. In this case, we default to the sensitive types.
247 return encrypted_types_;
248 }
249
250 void SyncServiceCrypto::OnPassphraseRequired(
251 PassphraseRequiredReason reason,
252 const sync_pb::EncryptedData& pending_keys) {
253 DCHECK(thread_checker_.CalledOnValidThread());
254
255 // Update our cache of the cryptographer's pending keys.
256 cached_pending_keys_ = pending_keys;
257
258 DVLOG(1) << "Passphrase required with reason: "
259 << PassphraseRequiredReasonToString(reason);
260 passphrase_required_reason_ = reason;
261
262 const ModelTypeSet types = get_preferred_types_.Run();
263 if (data_type_manager_) {
264 DCHECK(data_type_manager_->IsNigoriEnabled());
265 // Reconfigure without the encrypted types (excluded implicitly via the
266 // failed datatypes handler).
267 data_type_manager_->Configure(types, CONFIGURE_REASON_CRYPTO);
268 }
269
270 // Notify observers that the passphrase status may have changed.
271 notify_observers_.Run();
272 }
273
274 void SyncServiceCrypto::OnPassphraseAccepted() {
275 DCHECK(thread_checker_.CalledOnValidThread());
276
277 // Clear our cache of the cryptographer's pending keys.
278 cached_pending_keys_.clear_blob();
279
280 // If the pending keys were resolved via keystore, it's possible we never
281 // consumed our cached passphrase. Clear it now.
282 if (!cached_passphrase_.empty())
283 cached_passphrase_.clear();
284
285 // Reset passphrase_required_reason_ since we know we no longer require the
286 // passphrase.
287 passphrase_required_reason_ = REASON_PASSPHRASE_NOT_REQUIRED;
288
289 // Make sure the data types that depend on the passphrase are started at
290 // this time.
291 const ModelTypeSet types = get_preferred_types_.Run();
292 if (data_type_manager_) {
293 // Re-enable any encrypted types if necessary.
294 data_type_manager_->Configure(types, CONFIGURE_REASON_CRYPTO);
295 }
296
297 notify_observers_.Run();
298 }
299
300 void SyncServiceCrypto::OnBootstrapTokenUpdated(
301 const std::string& bootstrap_token,
302 BootstrapTokenType type) {
303 DCHECK(thread_checker_.CalledOnValidThread());
304 CHECK(sync_prefs_);
305 if (type == PASSPHRASE_BOOTSTRAP_TOKEN) {
306 sync_prefs_->SetEncryptionBootstrapToken(bootstrap_token);
307 } else {
308 sync_prefs_->SetKeystoreEncryptionBootstrapToken(bootstrap_token);
309 }
310 }
311
312 void SyncServiceCrypto::OnEncryptedTypesChanged(ModelTypeSet encrypted_types,
313 bool encrypt_everything) {
314 DCHECK(thread_checker_.CalledOnValidThread());
315 encrypted_types_ = encrypted_types;
316 encrypt_everything_ = encrypt_everything;
317 DCHECK(encrypt_everything_allowed_ || !encrypt_everything_);
318 DVLOG(1) << "Encrypted types changed to "
319 << ModelTypeSetToString(encrypted_types_)
320 << " (encrypt everything is set to "
321 << (encrypt_everything_ ? "true" : "false") << ")";
322 DCHECK(encrypted_types_.Has(PASSWORDS));
323
324 notify_observers_.Run();
325 }
326
327 void SyncServiceCrypto::OnEncryptionComplete() {
328 DCHECK(thread_checker_.CalledOnValidThread());
329 DVLOG(1) << "Encryption complete";
330 if (encryption_pending_ && encrypt_everything_) {
331 encryption_pending_ = false;
332 // This is to nudge the integration tests when encryption is
333 // finished.
334 notify_observers_.Run();
335 }
336 }
337
338 void SyncServiceCrypto::OnCryptographerStateChanged(
339 Cryptographer* cryptographer) {
340 DCHECK(thread_checker_.CalledOnValidThread());
341 // Do nothing.
342 }
343
344 void SyncServiceCrypto::OnPassphraseTypeChanged(PassphraseType type,
345 base::Time passphrase_time) {
346 DCHECK(thread_checker_.CalledOnValidThread());
347 DVLOG(1) << "Passphrase type changed to " << PassphraseTypeToString(type);
348 cached_passphrase_type_ = type;
349 cached_explicit_passphrase_time_ = passphrase_time;
350 }
351
352 void SyncServiceCrypto::OnLocalSetPassphraseEncryption(
353 const SyncEncryptionHandler::NigoriState& nigori_state) {
354 DCHECK(thread_checker_.CalledOnValidThread());
355 if (!base::FeatureList::IsEnabled(
356 switches::kSyncClearDataOnPassphraseEncryption))
357 return;
358
359 // At this point the user has set a custom passphrase and we have received the
360 // updated nigori state. Time to cache the nigori state, and catch up the
361 // active data types.
362 UMA_HISTOGRAM_ENUMERATION("Sync.ClearServerDataEvents",
363 CLEAR_SERVER_DATA_STARTED, CLEAR_SERVER_DATA_MAX);
364 sync_prefs_->SetNigoriSpecificsForPassphraseTransition(
365 nigori_state.nigori_specifics);
366 sync_prefs_->SetPassphraseEncryptionTransitionInProgress(true);
367 BeginConfigureCatchUpBeforeClear();
368 }
369
370 void SyncServiceCrypto::BeginConfigureCatchUpBeforeClear() {
371 DCHECK(thread_checker_.CalledOnValidThread());
372 DCHECK(data_type_manager_);
373 DCHECK(!saved_nigori_state_);
374 saved_nigori_state_ = base::MakeUnique<SyncEncryptionHandler::NigoriState>();
375 sync_prefs_->GetNigoriSpecificsForPassphraseTransition(
376 &saved_nigori_state_->nigori_specifics);
377 const ModelTypeSet types = data_type_manager_->GetActiveDataTypes();
378 data_type_manager_->Configure(types, CONFIGURE_REASON_CATCH_UP);
379 }
380
381 std::unique_ptr<SyncEncryptionHandler::Observer>
382 SyncServiceCrypto::GetEncryptionObserverProxy() {
383 DCHECK(thread_checker_.CalledOnValidThread());
384 return base::MakeUnique<SyncEncryptionObserverProxy>(
385 weak_factory_.GetWeakPtr(), base::ThreadTaskRunnerHandle::Get());
386 }
387
388 std::unique_ptr<SyncEncryptionHandler::NigoriState>
389 SyncServiceCrypto::TakeSavedNigoriState() {
390 DCHECK(thread_checker_.CalledOnValidThread());
391 return std::move(saved_nigori_state_);
392 }
393
394 void SyncServiceCrypto::ConsumeCachedPassphraseIfPossible() {
395 DCHECK(thread_checker_.CalledOnValidThread());
396
397 // If no cached passphrase, or sync engine hasn't started up yet, just exit.
398 // If the engine isn't running yet, OnEngineInitialized() will call this
399 // method again after the engine starts up.
400 if (cached_passphrase_.empty() || !engine_)
401 return;
402
403 // Engine is up and running, so we can consume the cached passphrase.
404 std::string passphrase = cached_passphrase_;
405 cached_passphrase_.clear();
406
407 // If we need a passphrase to decrypt data, try the cached passphrase.
408 if (passphrase_required_reason() == REASON_DECRYPTION) {
409 if (SetDecryptionPassphrase(passphrase)) {
410 DVLOG(1) << "Cached passphrase successfully decrypted pending keys";
411 return;
412 }
413 }
414
415 // If we get here, we don't have pending keys (or at least, the passphrase
416 // doesn't decrypt them) - just try to re-encrypt using the encryption
417 // passphrase.
418 if (!IsUsingSecondaryPassphrase())
419 SetEncryptionPassphrase(passphrase, false);
420 }
421
422 bool SyncServiceCrypto::CheckPassphraseAgainstCachedPendingKeys(
423 const std::string& passphrase) const {
424 DCHECK(cached_pending_keys_.has_blob());
425 DCHECK(!passphrase.empty());
426 Nigori nigori;
427 nigori.InitByDerivation("localhost", "dummy", passphrase);
428 std::string plaintext;
429 bool result = nigori.Decrypt(cached_pending_keys_.blob(), &plaintext);
430 DVLOG_IF(1, result) << "Passphrase failed to decrypt pending keys.";
431 return result;
432 }
433
434 } // namespace syncer
OLDNEW
« no previous file with comments | « components/sync/driver/sync_service_crypto.h ('k') | components/sync/engine/fake_sync_engine.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698