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