OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "sync/internal_api/sync_encryption_handler_impl.h" | 5 #include "sync/internal_api/sync_encryption_handler_impl.h" |
6 | 6 |
7 #include <queue> | 7 #include <queue> |
8 #include <string> | 8 #include <string> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/message_loop.h" | 11 #include "base/message_loop.h" |
12 #include "base/tracked_objects.h" | 12 #include "base/tracked_objects.h" |
13 #include "base/metrics/histogram.h" | 13 #include "base/metrics/histogram.h" |
14 #include "sync/internal_api/public/read_node.h" | 14 #include "sync/internal_api/public/read_node.h" |
15 #include "sync/internal_api/public/read_transaction.h" | 15 #include "sync/internal_api/public/read_transaction.h" |
16 #include "sync/internal_api/public/user_share.h" | |
17 #include "sync/internal_api/public/util/experiments.h" | 16 #include "sync/internal_api/public/util/experiments.h" |
18 #include "sync/internal_api/public/write_node.h" | 17 #include "sync/internal_api/public/write_node.h" |
19 #include "sync/internal_api/public/write_transaction.h" | 18 #include "sync/internal_api/public/write_transaction.h" |
20 #include "sync/protocol/encryption.pb.h" | 19 #include "sync/protocol/encryption.pb.h" |
21 #include "sync/protocol/nigori_specifics.pb.h" | 20 #include "sync/protocol/nigori_specifics.pb.h" |
21 #include "sync/protocol/sync.pb.h" | |
22 #include "sync/syncable/base_transaction.h" | 22 #include "sync/syncable/base_transaction.h" |
23 #include "sync/syncable/directory.h" | 23 #include "sync/syncable/directory.h" |
24 #include "sync/syncable/entry.h" | 24 #include "sync/syncable/entry.h" |
25 #include "sync/syncable/nigori_util.h" | 25 #include "sync/syncable/nigori_util.h" |
26 #include "sync/util/cryptographer.h" | 26 #include "sync/util/cryptographer.h" |
27 | 27 |
28 namespace syncer { | 28 namespace syncer { |
29 | 29 |
30 namespace { | 30 namespace { |
31 // The maximum number of times we will automatically overwrite the nigori node | 31 // The maximum number of times we will automatically overwrite the nigori node |
32 // because the encryption keys don't match (per chrome instantiation). | 32 // because the encryption keys don't match (per chrome instantiation). |
33 // We protect ourselves against nigori rollbacks, but it's possible two | 33 // We protect ourselves against nigori rollbacks, but it's possible two |
34 // different clients might have contrasting view of what the nigori node state | 34 // different clients might have contrasting view of what the nigori node state |
35 // should be, in which case they might ping pong (see crbug.com/119207). | 35 // should be, in which case they might ping pong (see crbug.com/119207). |
36 static const int kNigoriOverwriteLimit = 10; | 36 static const int kNigoriOverwriteLimit = 10; |
37 } | 37 } |
38 | 38 |
39 template <typename T> | |
40 const T& TransactionalHolder<T>::Get( | |
41 syncable::BaseTransaction* const trans) const { | |
42 DCHECK_EQ(user_share_->directory.get(), trans->directory()); | |
43 return *obj_; | |
44 } | |
45 | |
46 template <typename T> | |
47 T* TransactionalHolder<T>::GetMutable( | |
48 syncable::BaseTransaction* const trans) { | |
49 DCHECK_EQ(user_share_->directory.get(), trans->directory()); | |
50 return obj_; | |
51 } | |
52 | |
39 SyncEncryptionHandlerImpl::SyncEncryptionHandlerImpl( | 53 SyncEncryptionHandlerImpl::SyncEncryptionHandlerImpl( |
40 UserShare* user_share, | 54 UserShare* user_share, |
41 Cryptographer* cryptographer) | 55 Encryptor* encryptor) |
42 : weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), | 56 : weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), |
43 user_share_(user_share), | 57 user_share_(user_share), |
44 cryptographer_(cryptographer), | 58 cryptographer_unsafe_(encryptor), |
45 encrypted_types_(SensitiveTypes()), | 59 encrypted_types_unsafe_(SensitiveTypes()), |
60 cryptographer_holder_(user_share_, &cryptographer_unsafe_), | |
61 encrypted_types_holder_(user_share_, &encrypted_types_unsafe_), | |
46 encrypt_everything_(false), | 62 encrypt_everything_(false), |
47 explicit_passphrase_(false), | 63 explicit_passphrase_(false), |
48 nigori_overwrite_count_(0) { | 64 nigori_overwrite_count_(0) { |
49 } | 65 } |
50 | 66 |
51 SyncEncryptionHandlerImpl::~SyncEncryptionHandlerImpl() {} | 67 SyncEncryptionHandlerImpl::~SyncEncryptionHandlerImpl() {} |
52 | 68 |
53 void SyncEncryptionHandlerImpl::AddObserver(Observer* observer) { | 69 void SyncEncryptionHandlerImpl::AddObserver(Observer* observer) { |
70 DCHECK(thread_checker_.CalledOnValidThread()); | |
54 DCHECK(!observers_.HasObserver(observer)); | 71 DCHECK(!observers_.HasObserver(observer)); |
55 observers_.AddObserver(observer); | 72 observers_.AddObserver(observer); |
56 } | 73 } |
57 | 74 |
58 void SyncEncryptionHandlerImpl::RemoveObserver(Observer* observer) { | 75 void SyncEncryptionHandlerImpl::RemoveObserver(Observer* observer) { |
76 DCHECK(thread_checker_.CalledOnValidThread()); | |
59 DCHECK(observers_.HasObserver(observer)); | 77 DCHECK(observers_.HasObserver(observer)); |
60 observers_.RemoveObserver(observer); | 78 observers_.RemoveObserver(observer); |
61 } | 79 } |
62 | 80 |
63 void SyncEncryptionHandlerImpl::Init() { | 81 void SyncEncryptionHandlerImpl::Init() { |
82 DCHECK(thread_checker_.CalledOnValidThread()); | |
64 WriteTransaction trans(FROM_HERE, user_share_); | 83 WriteTransaction trans(FROM_HERE, user_share_); |
65 WriteNode node(&trans); | 84 WriteNode node(&trans); |
66 Cryptographer* cryptographer = trans.GetCryptographer(); | |
67 cryptographer_ = cryptographer; | |
68 | 85 |
69 if (node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK) | 86 if (node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK) |
70 return; | 87 return; |
71 if (!ApplyNigoriUpdateImpl(node.GetNigoriSpecifics(), | 88 if (!ApplyNigoriUpdateImpl(node.GetNigoriSpecifics(), |
72 trans.GetWrappedTrans())) { | 89 trans.GetWrappedTrans())) { |
73 WriteEncryptionStateToNigori(&trans); | 90 WriteEncryptionStateToNigori(&trans); |
74 } | 91 } |
75 | 92 |
76 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, | 93 // Always trigger an encrypted types and cryptographer state change event at |
77 OnCryptographerStateChanged(cryptographer)); | 94 // init time so observers get the initial values. |
95 FOR_EACH_OBSERVER( | |
96 Observer, observers_, | |
97 OnEncryptedTypesChanged( | |
98 encrypted_types_holder_.Get(trans.GetWrappedTrans()), | |
99 encrypt_everything_)); | |
100 FOR_EACH_OBSERVER( | |
101 SyncEncryptionHandler::Observer, | |
102 observers_, | |
103 OnCryptographerStateChanged( | |
104 cryptographer_holder_.GetMutable(trans.GetWrappedTrans()))); | |
78 | 105 |
79 // If the cryptographer is not ready (either it has pending keys or we | 106 // If the cryptographer is not ready (either it has pending keys or we |
80 // failed to initialize it), we don't want to try and re-encrypt the data. | 107 // failed to initialize it), we don't want to try and re-encrypt the data. |
81 // If we had encrypted types, the DataTypeManager will block, preventing | 108 // If we had encrypted types, the DataTypeManager will block, preventing |
82 // sync from happening until the the passphrase is provided. | 109 // sync from happening until the the passphrase is provided. |
83 if (cryptographer->is_ready()) | 110 if (cryptographer_holder_.Get(trans.GetWrappedTrans()).is_ready()) |
84 ReEncryptEverything(&trans); | 111 ReEncryptEverything(&trans); |
85 } | 112 } |
86 | 113 |
87 // Note: this is called from within a syncable transaction, so we need to post | |
88 // tasks if we want to do any work that creates a new sync_api transaction. | |
89 void SyncEncryptionHandlerImpl::ApplyNigoriUpdate( | |
90 const sync_pb::NigoriSpecifics& nigori, | |
91 syncable::BaseTransaction* const trans) { | |
92 DCHECK(trans); | |
93 if (!ApplyNigoriUpdateImpl(nigori, trans)) { | |
94 MessageLoop::current()->PostTask( | |
95 FROM_HERE, | |
96 base::Bind(&SyncEncryptionHandlerImpl::RewriteNigori, | |
97 weak_ptr_factory_.GetWeakPtr())); | |
98 } | |
99 | |
100 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, | |
101 OnCryptographerStateChanged(cryptographer_)); | |
102 } | |
103 | |
104 // Note: this is always called via the Cryptographer interface right now, | |
105 // so a transaction is already held. Once we remove that interface, we'll | |
106 // need to enforce holding a transaction when calling this method. | |
107 ModelTypeSet SyncEncryptionHandlerImpl::GetEncryptedTypes() const { | |
108 return encrypted_types_; | |
109 } | |
110 | |
111 void SyncEncryptionHandlerImpl::SetEncryptionPassphrase( | 114 void SyncEncryptionHandlerImpl::SetEncryptionPassphrase( |
112 const std::string& passphrase, | 115 const std::string& passphrase, |
113 bool is_explicit) { | 116 bool is_explicit) { |
117 DCHECK(thread_checker_.CalledOnValidThread()); | |
114 // We do not accept empty passphrases. | 118 // We do not accept empty passphrases. |
115 if (passphrase.empty()) { | 119 if (passphrase.empty()) { |
116 NOTREACHED() << "Cannot encrypt with an empty passphrase."; | 120 NOTREACHED() << "Cannot encrypt with an empty passphrase."; |
117 return; | 121 return; |
118 } | 122 } |
119 | 123 |
120 // All accesses to the cryptographer are protected by a transaction. | 124 // All accesses to the cryptographer are protected by a transaction. |
121 WriteTransaction trans(FROM_HERE, user_share_); | 125 WriteTransaction trans(FROM_HERE, user_share_); |
122 Cryptographer* cryptographer = trans.GetCryptographer(); | |
123 KeyParams key_params = {"localhost", "dummy", passphrase}; | 126 KeyParams key_params = {"localhost", "dummy", passphrase}; |
124 WriteNode node(&trans); | 127 WriteNode node(&trans); |
125 if (node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK) { | 128 if (node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK) { |
126 NOTREACHED(); | 129 NOTREACHED(); |
127 return; | 130 return; |
128 } | 131 } |
129 | 132 |
130 bool nigori_has_explicit_passphrase = | 133 bool nigori_has_explicit_passphrase = |
131 node.GetNigoriSpecifics().using_explicit_passphrase(); | 134 node.GetNigoriSpecifics().using_explicit_passphrase(); |
132 std::string bootstrap_token; | 135 std::string bootstrap_token; |
133 sync_pb::EncryptedData pending_keys; | 136 sync_pb::EncryptedData pending_keys; |
137 Cryptographer* cryptographer = | |
138 cryptographer_holder_.GetMutable(trans.GetWrappedTrans()); | |
134 if (cryptographer->has_pending_keys()) | 139 if (cryptographer->has_pending_keys()) |
135 pending_keys = cryptographer->GetPendingKeys(); | 140 pending_keys = cryptographer->GetPendingKeys(); |
136 bool success = false; | 141 bool success = false; |
137 | 142 |
138 | |
139 // There are six cases to handle here: | 143 // There are six cases to handle here: |
140 // 1. The user has no pending keys and is setting their current GAIA password | 144 // 1. The user has no pending keys and is setting their current GAIA password |
141 // as the encryption passphrase. This happens either during first time sync | 145 // as the encryption passphrase. This happens either during first time sync |
142 // with a clean profile, or after re-authenticating on a profile that was | 146 // with a clean profile, or after re-authenticating on a profile that was |
143 // already signed in with the cryptographer ready. | 147 // already signed in with the cryptographer ready. |
144 // 2. The user has no pending keys, and is overwriting an (already provided) | 148 // 2. The user has no pending keys, and is overwriting an (already provided) |
145 // implicit passphrase with an explicit (custom) passphrase. | 149 // implicit passphrase with an explicit (custom) passphrase. |
146 // 3. The user has pending keys for an explicit passphrase that is somehow set | 150 // 3. The user has pending keys for an explicit passphrase that is somehow set |
147 // to their current GAIA passphrase. | 151 // to their current GAIA passphrase. |
148 // 4. The user has pending keys encrypted with their current GAIA passphrase | 152 // 4. The user has pending keys encrypted with their current GAIA passphrase |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
217 DVLOG_IF(1, success) | 221 DVLOG_IF(1, success) |
218 << "Successfully set encryption passphrase; updating nigori and " | 222 << "Successfully set encryption passphrase; updating nigori and " |
219 "reencrypting."; | 223 "reencrypting."; |
220 | 224 |
221 FinishSetPassphrase( | 225 FinishSetPassphrase( |
222 success, bootstrap_token, is_explicit, &trans, &node); | 226 success, bootstrap_token, is_explicit, &trans, &node); |
223 } | 227 } |
224 | 228 |
225 void SyncEncryptionHandlerImpl::SetDecryptionPassphrase( | 229 void SyncEncryptionHandlerImpl::SetDecryptionPassphrase( |
226 const std::string& passphrase) { | 230 const std::string& passphrase) { |
231 DCHECK(thread_checker_.CalledOnValidThread()); | |
227 // We do not accept empty passphrases. | 232 // We do not accept empty passphrases. |
228 if (passphrase.empty()) { | 233 if (passphrase.empty()) { |
229 NOTREACHED() << "Cannot decrypt with an empty passphrase."; | 234 NOTREACHED() << "Cannot decrypt with an empty passphrase."; |
230 return; | 235 return; |
231 } | 236 } |
232 | 237 |
233 // All accesses to the cryptographer are protected by a transaction. | 238 // All accesses to the cryptographer are protected by a transaction. |
234 WriteTransaction trans(FROM_HERE, user_share_); | 239 WriteTransaction trans(FROM_HERE, user_share_); |
235 Cryptographer* cryptographer = trans.GetCryptographer(); | |
236 KeyParams key_params = {"localhost", "dummy", passphrase}; | 240 KeyParams key_params = {"localhost", "dummy", passphrase}; |
237 WriteNode node(&trans); | 241 WriteNode node(&trans); |
238 if (node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK) { | 242 if (node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK) { |
239 NOTREACHED(); | 243 NOTREACHED(); |
240 return; | 244 return; |
241 } | 245 } |
242 | 246 |
247 Cryptographer* cryptographer = | |
248 cryptographer_holder_.GetMutable(trans.GetWrappedTrans()); | |
243 if (!cryptographer->has_pending_keys()) { | 249 if (!cryptographer->has_pending_keys()) { |
244 // Note that this *can* happen in a rare situation where data is | 250 // Note that this *can* happen in a rare situation where data is |
245 // re-encrypted on another client while a SetDecryptionPassphrase() call is | 251 // re-encrypted on another client while a SetDecryptionPassphrase() call is |
246 // in-flight on this client. It is rare enough that we choose to do nothing. | 252 // in-flight on this client. It is rare enough that we choose to do nothing. |
247 NOTREACHED() << "Attempt to set decryption passphrase failed because there " | 253 NOTREACHED() << "Attempt to set decryption passphrase failed because there " |
248 << "were no pending keys."; | 254 << "were no pending keys."; |
249 return; | 255 return; |
250 } | 256 } |
251 | 257 |
252 bool nigori_has_explicit_passphrase = | 258 bool nigori_has_explicit_passphrase = |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
357 "reencrypting."; | 363 "reencrypting."; |
358 | 364 |
359 FinishSetPassphrase(success, | 365 FinishSetPassphrase(success, |
360 bootstrap_token, | 366 bootstrap_token, |
361 nigori_has_explicit_passphrase, | 367 nigori_has_explicit_passphrase, |
362 &trans, | 368 &trans, |
363 &node); | 369 &node); |
364 } | 370 } |
365 | 371 |
366 void SyncEncryptionHandlerImpl::EnableEncryptEverything() { | 372 void SyncEncryptionHandlerImpl::EnableEncryptEverything() { |
373 DCHECK(thread_checker_.CalledOnValidThread()); | |
374 WriteTransaction trans(FROM_HERE, user_share_); | |
375 ModelTypeSet* encrypted_types = | |
376 encrypted_types_holder_.GetMutable(trans.GetWrappedTrans()); | |
367 if (encrypt_everything_) { | 377 if (encrypt_everything_) { |
368 DCHECK(encrypted_types_.Equals(ModelTypeSet::All())); | 378 DCHECK(encrypted_types->Equals(ModelTypeSet::All())); |
369 return; | 379 return; |
370 } | 380 } |
371 WriteTransaction trans(FROM_HERE, user_share_); | 381 DVLOG(1) << "Enabling encrypt everything."; |
372 encrypt_everything_ = true; | 382 encrypt_everything_ = true; |
373 // Change |encrypted_types_| directly to avoid sending more than one | 383 // Change |encrypted_types_| directly to avoid sending more than one |
374 // notification. | 384 // notification. |
375 encrypted_types_ = ModelTypeSet::All(); | 385 *encrypted_types = ModelTypeSet::All(); |
376 FOR_EACH_OBSERVER( | 386 FOR_EACH_OBSERVER( |
377 Observer, observers_, | 387 Observer, observers_, |
378 OnEncryptedTypesChanged(encrypted_types_, encrypt_everything_)); | 388 OnEncryptedTypesChanged(*encrypted_types, encrypt_everything_)); |
379 WriteEncryptionStateToNigori(&trans); | 389 WriteEncryptionStateToNigori(&trans); |
380 ReEncryptEverything(&trans); | 390 if (cryptographer_holder_.Get(trans.GetWrappedTrans()).is_ready()) |
391 ReEncryptEverything(&trans); | |
381 } | 392 } |
382 | 393 |
383 bool SyncEncryptionHandlerImpl::EncryptEverythingEnabled() const { | 394 bool SyncEncryptionHandlerImpl::EncryptEverythingEnabled() const { |
384 ReadTransaction trans(FROM_HERE, user_share_); | 395 DCHECK(thread_checker_.CalledOnValidThread()); |
385 return encrypt_everything_; | 396 return encrypt_everything_; |
386 } | 397 } |
387 | 398 |
388 bool SyncEncryptionHandlerImpl::IsUsingExplicitPassphrase() const { | 399 bool SyncEncryptionHandlerImpl::IsUsingExplicitPassphrase() const { |
400 // TODO(zea): this is called from the UI thread, so we have to have a | |
401 // transaction while accessing it. Add an OnPassphraseTypeChanged observer | |
402 // and have the SBH cache the value on the UI thread. | |
389 ReadTransaction trans(FROM_HERE, user_share_); | 403 ReadTransaction trans(FROM_HERE, user_share_); |
390 return explicit_passphrase_; | 404 return explicit_passphrase_; |
391 } | 405 } |
392 | 406 |
407 // Note: this is called from within a syncable transaction, so we need to post | |
408 // tasks if we want to do any work that creates a new sync_api transaction. | |
409 void SyncEncryptionHandlerImpl::ApplyNigoriUpdate( | |
410 const sync_pb::NigoriSpecifics& nigori, | |
411 syncable::BaseTransaction* const trans) { | |
412 DCHECK(thread_checker_.CalledOnValidThread()); | |
413 DCHECK(trans); | |
414 if (!ApplyNigoriUpdateImpl(nigori, trans)) { | |
415 MessageLoop::current()->PostTask( | |
416 FROM_HERE, | |
417 base::Bind(&SyncEncryptionHandlerImpl::RewriteNigori, | |
418 weak_ptr_factory_.GetWeakPtr())); | |
419 } | |
420 | |
421 FOR_EACH_OBSERVER( | |
422 SyncEncryptionHandler::Observer, | |
423 observers_, | |
424 OnCryptographerStateChanged( | |
tim (not reviewing)
2012/08/23 18:38:10
Should we bubble the trans up through this observe
Nicolas Zea
2012/08/23 22:49:32
We'd have to do that with most other observer meth
| |
425 cryptographer_holder_.GetMutable(trans))); | |
426 } | |
427 | |
428 void SyncEncryptionHandlerImpl::UpdateNigoriFromEncryptedTypes( | |
429 sync_pb::NigoriSpecifics* nigori, | |
430 syncable::BaseTransaction* const trans) const { | |
431 syncable::UpdateNigoriFromEncryptedTypes(encrypted_types_holder_.Get(trans), | |
432 encrypt_everything_, | |
433 nigori); | |
434 } | |
435 | |
436 ModelTypeSet SyncEncryptionHandlerImpl::GetEncryptedTypes( | |
437 syncable::BaseTransaction* const trans) const { | |
438 return encrypted_types_holder_.Get(trans); | |
439 } | |
440 | |
393 // This function iterates over all encrypted types. There are many scenarios in | 441 // This function iterates over all encrypted types. There are many scenarios in |
394 // which data for some or all types is not currently available. In that case, | 442 // which data for some or all types is not currently available. In that case, |
395 // the lookup of the root node will fail and we will skip encryption for that | 443 // the lookup of the root node will fail and we will skip encryption for that |
396 // type. | 444 // type. |
397 void SyncEncryptionHandlerImpl::ReEncryptEverything( | 445 void SyncEncryptionHandlerImpl::ReEncryptEverything( |
398 WriteTransaction* trans) { | 446 WriteTransaction* trans) { |
399 Cryptographer* cryptographer = trans->GetCryptographer(); | 447 DCHECK(thread_checker_.CalledOnValidThread()); |
400 if (!cryptographer->is_ready()) | 448 DCHECK(cryptographer_holder_.Get(trans->GetWrappedTrans()).is_ready()); |
401 return; | 449 for (ModelTypeSet::Iterator iter = encrypted_types_holder_.Get( |
402 ModelTypeSet encrypted_types = GetEncryptedTypes(); | 450 trans->GetWrappedTrans()).First(); |
403 for (ModelTypeSet::Iterator iter = encrypted_types.First(); | |
404 iter.Good(); iter.Inc()) { | 451 iter.Good(); iter.Inc()) { |
405 if (iter.Get() == PASSWORDS || iter.Get() == NIGORI) | 452 if (iter.Get() == PASSWORDS || iter.Get() == NIGORI) |
406 continue; // These types handle encryption differently. | 453 continue; // These types handle encryption differently. |
407 | 454 |
408 ReadNode type_root(trans); | 455 ReadNode type_root(trans); |
409 std::string tag = ModelTypeToRootTag(iter.Get()); | 456 std::string tag = ModelTypeToRootTag(iter.Get()); |
410 if (type_root.InitByTagLookup(tag) != BaseNode::INIT_OK) | 457 if (type_root.InitByTagLookup(tag) != BaseNode::INIT_OK) |
411 continue; // Don't try to reencrypt if the type's data is unavailable. | 458 continue; // Don't try to reencrypt if the type's data is unavailable. |
412 | 459 |
413 // Iterate through all children of this datatype. | 460 // Iterate through all children of this datatype. |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
448 WriteNode child(trans); | 495 WriteNode child(trans); |
449 if (child.InitByIdLookup(child_id) != BaseNode::INIT_OK) { | 496 if (child.InitByIdLookup(child_id) != BaseNode::INIT_OK) { |
450 NOTREACHED(); | 497 NOTREACHED(); |
451 return; | 498 return; |
452 } | 499 } |
453 child.SetPasswordSpecifics(child.GetPasswordSpecifics()); | 500 child.SetPasswordSpecifics(child.GetPasswordSpecifics()); |
454 child_id = child.GetSuccessorId(); | 501 child_id = child.GetSuccessorId(); |
455 } | 502 } |
456 } | 503 } |
457 | 504 |
505 DVLOG(1) << "Re-encrypt everything complete."; | |
506 | |
458 // NOTE: We notify from within a transaction. | 507 // NOTE: We notify from within a transaction. |
459 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, | 508 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, |
460 OnEncryptionComplete()); | 509 OnEncryptionComplete()); |
461 } | 510 } |
462 | 511 |
463 bool SyncEncryptionHandlerImpl::ApplyNigoriUpdateImpl( | 512 bool SyncEncryptionHandlerImpl::ApplyNigoriUpdateImpl( |
464 const sync_pb::NigoriSpecifics& nigori, | 513 const sync_pb::NigoriSpecifics& nigori, |
465 syncable::BaseTransaction* const trans) { | 514 syncable::BaseTransaction* const trans) { |
466 Cryptographer* cryptographer = trans->directory()->GetCryptographer(trans); | 515 DCHECK(thread_checker_.CalledOnValidThread()); |
467 bool nigori_types_need_update = !UpdateEncryptedTypesFromNigori(nigori); | 516 bool nigori_types_need_update = !UpdateEncryptedTypesFromNigori(nigori, |
517 trans); | |
468 if (nigori.using_explicit_passphrase()) | 518 if (nigori.using_explicit_passphrase()) |
469 explicit_passphrase_ = true; | 519 explicit_passphrase_ = true; |
470 | 520 |
521 Cryptographer* cryptographer = cryptographer_holder_.GetMutable(trans); | |
471 bool nigori_needs_new_keys = false; | 522 bool nigori_needs_new_keys = false; |
472 if (!nigori.encrypted().blob().empty()) { | 523 if (!nigori.encrypted().blob().empty()) { |
473 if (cryptographer->CanDecrypt(nigori.encrypted())) { | 524 if (cryptographer->CanDecrypt(nigori.encrypted())) { |
474 cryptographer->InstallKeys(nigori.encrypted()); | 525 cryptographer->InstallKeys(nigori.encrypted()); |
475 // We only update the default passphrase if this was a new explicit | 526 // We only update the default passphrase if this was a new explicit |
476 // passphrase. Else, since it was decryptable, it must not have been a new | 527 // passphrase. Else, since it was decryptable, it must not have been a new |
477 // key. | 528 // key. |
478 if (nigori.using_explicit_passphrase()) | 529 if (nigori.using_explicit_passphrase()) |
479 cryptographer->SetDefaultKey(nigori.encrypted().key_name()); | 530 cryptographer->SetDefaultKey(nigori.encrypted().key_name()); |
480 | 531 |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
515 if (nigori.using_explicit_passphrase() != explicit_passphrase_ || | 566 if (nigori.using_explicit_passphrase() != explicit_passphrase_ || |
516 nigori.encrypt_everything() != encrypt_everything_ || | 567 nigori.encrypt_everything() != encrypt_everything_ || |
517 nigori_types_need_update || | 568 nigori_types_need_update || |
518 nigori_needs_new_keys) { | 569 nigori_needs_new_keys) { |
519 return false; | 570 return false; |
520 } | 571 } |
521 return true; | 572 return true; |
522 } | 573 } |
523 | 574 |
524 void SyncEncryptionHandlerImpl::RewriteNigori() { | 575 void SyncEncryptionHandlerImpl::RewriteNigori() { |
576 DVLOG(1) << "Overwriting stale nigori node."; | |
577 DCHECK(thread_checker_.CalledOnValidThread()); | |
525 WriteTransaction trans(FROM_HERE, user_share_); | 578 WriteTransaction trans(FROM_HERE, user_share_); |
526 WriteEncryptionStateToNigori(&trans); | 579 WriteEncryptionStateToNigori(&trans); |
527 } | 580 } |
528 | 581 |
529 void SyncEncryptionHandlerImpl::WriteEncryptionStateToNigori( | 582 void SyncEncryptionHandlerImpl::WriteEncryptionStateToNigori( |
530 WriteTransaction* trans) { | 583 WriteTransaction* trans) { |
584 DCHECK(thread_checker_.CalledOnValidThread()); | |
531 WriteNode nigori_node(trans); | 585 WriteNode nigori_node(trans); |
532 // This can happen in tests that don't have nigori nodes. | 586 // This can happen in tests that don't have nigori nodes. |
533 if (!nigori_node.InitByTagLookup(kNigoriTag) == BaseNode::INIT_OK) | 587 if (nigori_node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK) |
534 return; | 588 return; |
535 sync_pb::NigoriSpecifics nigori = nigori_node.GetNigoriSpecifics(); | 589 sync_pb::NigoriSpecifics nigori = nigori_node.GetNigoriSpecifics(); |
536 Cryptographer* cryptographer = trans->GetCryptographer(); | 590 const Cryptographer& cryptographer = cryptographer_holder_.Get( |
537 if (cryptographer->is_ready() && | 591 trans->GetWrappedTrans()); |
592 if (cryptographer.is_ready() && | |
538 nigori_overwrite_count_ < kNigoriOverwriteLimit) { | 593 nigori_overwrite_count_ < kNigoriOverwriteLimit) { |
539 // Does not modify the encrypted blob if the unencrypted data already | 594 // Does not modify the encrypted blob if the unencrypted data already |
540 // matches what is about to be written. | 595 // matches what is about to be written. |
541 sync_pb::EncryptedData original_keys = nigori.encrypted(); | 596 sync_pb::EncryptedData original_keys = nigori.encrypted(); |
542 if (!cryptographer->GetKeys(nigori.mutable_encrypted())) | 597 if (!cryptographer.GetKeys(nigori.mutable_encrypted())) |
543 NOTREACHED(); | 598 NOTREACHED(); |
544 | 599 |
545 if (nigori.encrypted().SerializeAsString() != | 600 if (nigori.encrypted().SerializeAsString() != |
546 original_keys.SerializeAsString()) { | 601 original_keys.SerializeAsString()) { |
547 // We've updated the nigori node's encryption keys. In order to prevent | 602 // We've updated the nigori node's encryption keys. In order to prevent |
548 // a possible looping of two clients constantly overwriting each other, | 603 // a possible looping of two clients constantly overwriting each other, |
549 // we limit the absolute number of overwrites per client instantiation. | 604 // we limit the absolute number of overwrites per client instantiation. |
550 nigori_overwrite_count_++; | 605 nigori_overwrite_count_++; |
551 UMA_HISTOGRAM_COUNTS("Sync.AutoNigoriOverwrites", | 606 UMA_HISTOGRAM_COUNTS("Sync.AutoNigoriOverwrites", |
552 nigori_overwrite_count_); | 607 nigori_overwrite_count_); |
553 } | 608 } |
554 | 609 |
555 // Note: we don't try to set using_explicit_passphrase here since if that | 610 // Note: we don't try to set using_explicit_passphrase here since if that |
556 // is lost the user can always set it again. The main point is to preserve | 611 // is lost the user can always set it again. The main point is to preserve |
557 // the encryption keys so all data remains decryptable. | 612 // the encryption keys so all data remains decryptable. |
558 } | 613 } |
559 syncable::UpdateNigoriFromEncryptedTypes(encrypted_types_, | 614 syncable::UpdateNigoriFromEncryptedTypes( |
560 encrypt_everything_, | 615 encrypted_types_holder_.Get(trans->GetWrappedTrans()), |
561 &nigori); | 616 encrypt_everything_, |
617 &nigori); | |
562 | 618 |
563 // If nothing has changed, this is a no-op. | 619 // If nothing has changed, this is a no-op. |
564 nigori_node.SetNigoriSpecifics(nigori); | 620 nigori_node.SetNigoriSpecifics(nigori); |
565 } | 621 } |
566 | 622 |
567 bool SyncEncryptionHandlerImpl::UpdateEncryptedTypesFromNigori( | 623 bool SyncEncryptionHandlerImpl::UpdateEncryptedTypesFromNigori( |
568 const sync_pb::NigoriSpecifics& nigori) { | 624 const sync_pb::NigoriSpecifics& nigori, |
625 syncable::BaseTransaction* const trans) { | |
626 DCHECK(thread_checker_.CalledOnValidThread()); | |
627 ModelTypeSet* encrypted_types = encrypted_types_holder_.GetMutable(trans); | |
569 if (nigori.encrypt_everything()) { | 628 if (nigori.encrypt_everything()) { |
570 if (!encrypt_everything_) { | 629 if (!encrypt_everything_) { |
571 encrypt_everything_ = true; | 630 encrypt_everything_ = true; |
572 encrypted_types_ = ModelTypeSet::All(); | 631 *encrypted_types = ModelTypeSet::All(); |
632 DVLOG(1) << "Enabling encrypt everything via nigori node update"; | |
573 FOR_EACH_OBSERVER( | 633 FOR_EACH_OBSERVER( |
574 Observer, observers_, | 634 Observer, observers_, |
575 OnEncryptedTypesChanged(encrypted_types_, encrypt_everything_)); | 635 OnEncryptedTypesChanged(*encrypted_types, encrypt_everything_)); |
576 } | 636 } |
577 DCHECK(encrypted_types_.Equals(ModelTypeSet::All())); | 637 DCHECK(encrypted_types->Equals(ModelTypeSet::All())); |
578 return true; | 638 return true; |
579 } | 639 } |
580 | 640 |
581 ModelTypeSet encrypted_types; | 641 ModelTypeSet nigori_encrypted_types; |
582 encrypted_types = syncable::GetEncryptedTypesFromNigori(nigori); | 642 nigori_encrypted_types = syncable::GetEncryptedTypesFromNigori(nigori); |
583 encrypted_types.PutAll(SensitiveTypes()); | 643 nigori_encrypted_types.PutAll(SensitiveTypes()); |
584 | 644 |
585 // If anything more than the sensitive types were encrypted, and | 645 // If anything more than the sensitive types were encrypted, and |
586 // encrypt_everything is not explicitly set to false, we assume it means | 646 // encrypt_everything is not explicitly set to false, we assume it means |
587 // a client intended to enable encrypt everything. | 647 // a client intended to enable encrypt everything. |
588 if (!nigori.has_encrypt_everything() && | 648 if (!nigori.has_encrypt_everything() && |
589 !Difference(encrypted_types, SensitiveTypes()).Empty()) { | 649 !Difference(nigori_encrypted_types, SensitiveTypes()).Empty()) { |
590 if (!encrypt_everything_) { | 650 if (!encrypt_everything_) { |
591 encrypt_everything_ = true; | 651 encrypt_everything_ = true; |
592 encrypted_types_ = ModelTypeSet::All(); | 652 *encrypted_types = ModelTypeSet::All(); |
593 FOR_EACH_OBSERVER( | 653 FOR_EACH_OBSERVER( |
594 Observer, observers_, | 654 Observer, observers_, |
595 OnEncryptedTypesChanged(encrypted_types_, encrypt_everything_)); | 655 OnEncryptedTypesChanged(*encrypted_types, encrypt_everything_)); |
596 } | 656 } |
597 DCHECK(encrypted_types_.Equals(ModelTypeSet::All())); | 657 DCHECK(encrypted_types->Equals(ModelTypeSet::All())); |
598 return false; | 658 return false; |
599 } | 659 } |
600 | 660 |
601 MergeEncryptedTypes(encrypted_types); | 661 MergeEncryptedTypes(nigori_encrypted_types, trans); |
602 return encrypted_types_.Equals(encrypted_types); | 662 return encrypted_types->Equals(nigori_encrypted_types); |
603 } | |
604 | |
605 void SyncEncryptionHandlerImpl::UpdateNigoriFromEncryptedTypes( | |
606 sync_pb::NigoriSpecifics* nigori, | |
607 syncable::BaseTransaction* const trans) const { | |
608 syncable::UpdateNigoriFromEncryptedTypes(encrypted_types_, | |
609 encrypt_everything_, | |
610 nigori); | |
611 } | 663 } |
612 | 664 |
613 void SyncEncryptionHandlerImpl::FinishSetPassphrase( | 665 void SyncEncryptionHandlerImpl::FinishSetPassphrase( |
614 bool success, | 666 bool success, |
615 const std::string& bootstrap_token, | 667 const std::string& bootstrap_token, |
616 bool is_explicit, | 668 bool is_explicit, |
617 WriteTransaction* trans, | 669 WriteTransaction* trans, |
618 WriteNode* nigori_node) { | 670 WriteNode* nigori_node) { |
619 Cryptographer* cryptographer = trans->GetCryptographer(); | 671 DCHECK(thread_checker_.CalledOnValidThread()); |
620 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, | 672 FOR_EACH_OBSERVER( |
621 OnCryptographerStateChanged(cryptographer)); | 673 SyncEncryptionHandler::Observer, |
674 observers_, | |
675 OnCryptographerStateChanged( | |
676 cryptographer_holder_.GetMutable(trans->GetWrappedTrans()))); | |
622 | 677 |
623 // It's possible we need to change the bootstrap token even if we failed to | 678 // It's possible we need to change the bootstrap token even if we failed to |
624 // set the passphrase (for example if we need to preserve the new GAIA | 679 // set the passphrase (for example if we need to preserve the new GAIA |
625 // passphrase). | 680 // passphrase). |
626 if (!bootstrap_token.empty()) { | 681 if (!bootstrap_token.empty()) { |
627 DVLOG(1) << "Bootstrap token updated."; | 682 DVLOG(1) << "Bootstrap token updated."; |
628 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, | 683 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, |
629 OnBootstrapTokenUpdated(bootstrap_token)); | 684 OnBootstrapTokenUpdated(bootstrap_token)); |
630 } | 685 } |
631 | 686 |
687 const Cryptographer& cryptographer = | |
688 cryptographer_holder_.Get(trans->GetWrappedTrans()); | |
632 if (!success) { | 689 if (!success) { |
633 if (cryptographer->is_ready()) { | 690 if (cryptographer.is_ready()) { |
634 LOG(ERROR) << "Attempt to change passphrase failed while cryptographer " | 691 LOG(ERROR) << "Attempt to change passphrase failed while cryptographer " |
635 << "was ready."; | 692 << "was ready."; |
636 } else if (cryptographer->has_pending_keys()) { | 693 } else if (cryptographer.has_pending_keys()) { |
637 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, | 694 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, |
638 OnPassphraseRequired(REASON_DECRYPTION, | 695 OnPassphraseRequired(REASON_DECRYPTION, |
639 cryptographer->GetPendingKeys())); | 696 cryptographer.GetPendingKeys())); |
640 } else { | 697 } else { |
641 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, | 698 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, |
642 OnPassphraseRequired(REASON_ENCRYPTION, | 699 OnPassphraseRequired(REASON_ENCRYPTION, |
643 sync_pb::EncryptedData())); | 700 sync_pb::EncryptedData())); |
644 } | 701 } |
645 return; | 702 return; |
646 } | 703 } |
647 | 704 |
648 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, | 705 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, |
649 OnPassphraseAccepted()); | 706 OnPassphraseAccepted()); |
650 DCHECK(cryptographer->is_ready()); | 707 DCHECK(cryptographer.is_ready()); |
651 | 708 |
652 sync_pb::NigoriSpecifics specifics(nigori_node->GetNigoriSpecifics()); | 709 sync_pb::NigoriSpecifics specifics(nigori_node->GetNigoriSpecifics()); |
653 // Does not modify specifics.encrypted() if the original decrypted data was | 710 // Does not modify specifics.encrypted() if the original decrypted data was |
654 // the same. | 711 // the same. |
655 if (!cryptographer->GetKeys(specifics.mutable_encrypted())) { | 712 if (!cryptographer.GetKeys(specifics.mutable_encrypted())) |
656 NOTREACHED(); | 713 NOTREACHED(); |
657 return; | |
658 } | |
659 explicit_passphrase_ = is_explicit; | 714 explicit_passphrase_ = is_explicit; |
660 specifics.set_using_explicit_passphrase(is_explicit); | 715 specifics.set_using_explicit_passphrase(is_explicit); |
661 nigori_node->SetNigoriSpecifics(specifics); | 716 nigori_node->SetNigoriSpecifics(specifics); |
662 | 717 |
663 // Does nothing if everything is already encrypted or the cryptographer has | 718 // Does nothing if everything is already encrypted. |
664 // pending keys. | |
665 ReEncryptEverything(trans); | 719 ReEncryptEverything(trans); |
666 } | 720 } |
667 | 721 |
668 void SyncEncryptionHandlerImpl::MergeEncryptedTypes( | 722 void SyncEncryptionHandlerImpl::MergeEncryptedTypes( |
669 ModelTypeSet encrypted_types) { | 723 ModelTypeSet new_encrypted_types, |
670 if (!encrypted_types_.HasAll(encrypted_types)) { | 724 syncable::BaseTransaction* const trans) { |
671 encrypted_types_ = encrypted_types; | 725 DCHECK(thread_checker_.CalledOnValidThread()); |
726 ModelTypeSet* encrypted_types = encrypted_types_holder_.GetMutable(trans); | |
727 if (!encrypted_types->HasAll(new_encrypted_types)) { | |
728 *encrypted_types = new_encrypted_types; | |
672 FOR_EACH_OBSERVER( | 729 FOR_EACH_OBSERVER( |
673 Observer, observers_, | 730 Observer, observers_, |
674 OnEncryptedTypesChanged(encrypted_types_, encrypt_everything_)); | 731 OnEncryptedTypesChanged(*encrypted_types, encrypt_everything_)); |
675 } | 732 } |
676 } | 733 } |
677 | 734 |
678 } // namespace browser_sync | 735 } // namespace browser_sync |
OLD | NEW |