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

Side by Side Diff: chrome/browser/sync/engine/syncapi.cc

Issue 7108067: [Sync] Ensure cryptographer ready before encrypting. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase Created 9 years, 6 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 | Annotate | Revision Log
« no previous file with comments | « chrome/browser/sync/engine/syncapi.h ('k') | chrome/browser/sync/engine/syncapi_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 "chrome/browser/sync/engine/syncapi.h" 5 #include "chrome/browser/sync/engine/syncapi.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <bitset> 8 #include <bitset>
9 #include <iomanip> 9 #include <iomanip>
10 #include <list> 10 #include <list>
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after
195 } 195 }
196 } 196 }
197 197
198 UserShare::UserShare() {} 198 UserShare::UserShare() {}
199 199
200 UserShare::~UserShare() {} 200 UserShare::~UserShare() {}
201 201
202 //////////////////////////////////// 202 ////////////////////////////////////
203 // BaseNode member definitions. 203 // BaseNode member definitions.
204 204
205 BaseNode::BaseNode() {} 205 BaseNode::BaseNode() : password_data_(new sync_pb::PasswordSpecificsData) {}
206 206
207 BaseNode::~BaseNode() {} 207 BaseNode::~BaseNode() {}
208 208
209 std::string BaseNode::GenerateSyncableHash( 209 std::string BaseNode::GenerateSyncableHash(
210 syncable::ModelType model_type, const std::string& client_tag) { 210 syncable::ModelType model_type, const std::string& client_tag) {
211 // blank PB with just the extension in it has termination symbol, 211 // blank PB with just the extension in it has termination symbol,
212 // handy for delimiter 212 // handy for delimiter
213 sync_pb::EntitySpecifics serialized_type; 213 sync_pb::EntitySpecifics serialized_type;
214 syncable::AddDefaultExtensionValue(model_type, &serialized_type); 214 syncable::AddDefaultExtensionValue(model_type, &serialized_type);
215 std::string hash_input; 215 std::string hash_input;
(...skipping 22 matching lines...) Expand all
238 } 238 }
239 239
240 bool BaseNode::DecryptIfNecessary() { 240 bool BaseNode::DecryptIfNecessary() {
241 if (GetIsFolder()) return true; // Ignore the top-level datatype folder. 241 if (GetIsFolder()) return true; // Ignore the top-level datatype folder.
242 const sync_pb::EntitySpecifics& specifics = 242 const sync_pb::EntitySpecifics& specifics =
243 GetEntry()->Get(syncable::SPECIFICS); 243 GetEntry()->Get(syncable::SPECIFICS);
244 if (specifics.HasExtension(sync_pb::password)) { 244 if (specifics.HasExtension(sync_pb::password)) {
245 // Passwords have their own legacy encryption structure. 245 // Passwords have their own legacy encryption structure.
246 scoped_ptr<sync_pb::PasswordSpecificsData> data(DecryptPasswordSpecifics( 246 scoped_ptr<sync_pb::PasswordSpecificsData> data(DecryptPasswordSpecifics(
247 specifics, GetTransaction()->GetCryptographer())); 247 specifics, GetTransaction()->GetCryptographer()));
248 if (!data.get()) 248 if (!data.get()) {
249 LOG(ERROR) << "Failed to decrypt password specifics.";
249 return false; 250 return false;
251 }
250 password_data_.swap(data); 252 password_data_.swap(data);
251 return true; 253 return true;
252 } 254 }
253 255
254 // We assume any node with the encrypted field set has encrypted data. 256 // We assume any node with the encrypted field set has encrypted data.
255 if (!specifics.has_encrypted()) 257 if (!specifics.has_encrypted())
256 return true; 258 return true;
257 259
258 const sync_pb::EncryptedData& encrypted = 260 const sync_pb::EncryptedData& encrypted =
259 specifics.encrypted(); 261 specifics.encrypted();
260 std::string plaintext_data = GetTransaction()->GetCryptographer()-> 262 std::string plaintext_data = GetTransaction()->GetCryptographer()->
261 DecryptToString(encrypted); 263 DecryptToString(encrypted);
262 if (plaintext_data.length() == 0) 264 if (plaintext_data.length() == 0 ||
263 return false; 265 !unencrypted_data_.ParseFromString(plaintext_data)) {
264 if (!unencrypted_data_.ParseFromString(plaintext_data)) {
265 LOG(ERROR) << "Failed to decrypt encrypted node of type " << 266 LOG(ERROR) << "Failed to decrypt encrypted node of type " <<
266 syncable::ModelTypeToString(GetModelType()) << "."; 267 syncable::ModelTypeToString(GetModelType()) << ".";
267 return false; 268 return false;
268 } 269 }
269 return true; 270 return true;
270 } 271 }
271 272
272 const sync_pb::EntitySpecifics& BaseNode::GetUnencryptedSpecifics( 273 const sync_pb::EntitySpecifics& BaseNode::GetUnencryptedSpecifics(
273 const syncable::Entry* entry) const { 274 const syncable::Entry* entry) const {
274 const sync_pb::EntitySpecifics& specifics = entry->Get(SPECIFICS); 275 const sync_pb::EntitySpecifics& specifics = entry->Get(SPECIFICS);
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
397 return GetEntitySpecifics().GetExtension(sync_pb::bookmark); 398 return GetEntitySpecifics().GetExtension(sync_pb::bookmark);
398 } 399 }
399 400
400 const sync_pb::NigoriSpecifics& BaseNode::GetNigoriSpecifics() const { 401 const sync_pb::NigoriSpecifics& BaseNode::GetNigoriSpecifics() const {
401 DCHECK_EQ(syncable::NIGORI, GetModelType()); 402 DCHECK_EQ(syncable::NIGORI, GetModelType());
402 return GetEntitySpecifics().GetExtension(sync_pb::nigori); 403 return GetEntitySpecifics().GetExtension(sync_pb::nigori);
403 } 404 }
404 405
405 const sync_pb::PasswordSpecificsData& BaseNode::GetPasswordSpecifics() const { 406 const sync_pb::PasswordSpecificsData& BaseNode::GetPasswordSpecifics() const {
406 DCHECK_EQ(syncable::PASSWORDS, GetModelType()); 407 DCHECK_EQ(syncable::PASSWORDS, GetModelType());
407 DCHECK(password_data_.get());
408 return *password_data_; 408 return *password_data_;
409 } 409 }
410 410
411 const sync_pb::ThemeSpecifics& BaseNode::GetThemeSpecifics() const { 411 const sync_pb::ThemeSpecifics& BaseNode::GetThemeSpecifics() const {
412 DCHECK_EQ(syncable::THEMES, GetModelType()); 412 DCHECK_EQ(syncable::THEMES, GetModelType());
413 return GetEntitySpecifics().GetExtension(sync_pb::theme); 413 return GetEntitySpecifics().GetExtension(sync_pb::theme);
414 } 414 }
415 415
416 const sync_pb::TypedUrlSpecifics& BaseNode::GetTypedUrlSpecifics() const { 416 const sync_pb::TypedUrlSpecifics& BaseNode::GetTypedUrlSpecifics() const {
417 DCHECK_EQ(syncable::TYPED_URLS, GetModelType()); 417 DCHECK_EQ(syncable::TYPED_URLS, GetModelType());
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
564 scoped_ptr<sync_pb::PasswordSpecificsData> old_plaintext( 564 scoped_ptr<sync_pb::PasswordSpecificsData> old_plaintext(
565 DecryptPasswordSpecifics(GetEntry()->Get(SPECIFICS), cryptographer)); 565 DecryptPasswordSpecifics(GetEntry()->Get(SPECIFICS), cryptographer));
566 if (old_plaintext.get() && 566 if (old_plaintext.get() &&
567 old_plaintext->SerializeAsString() == data.SerializeAsString() && 567 old_plaintext->SerializeAsString() == data.SerializeAsString() &&
568 cryptographer->CanDecryptUsingDefaultKey(old_ciphertext)) { 568 cryptographer->CanDecryptUsingDefaultKey(old_ciphertext)) {
569 return; 569 return;
570 } 570 }
571 571
572 sync_pb::PasswordSpecifics new_value; 572 sync_pb::PasswordSpecifics new_value;
573 if (!cryptographer->Encrypt(data, new_value.mutable_encrypted())) { 573 if (!cryptographer->Encrypt(data, new_value.mutable_encrypted())) {
574 NOTREACHED(); 574 NOTREACHED() << "Failed to encrypt password, possibly due to sync node "
575 << "corruption";
576 return;
575 } 577 }
576 578
577 sync_pb::EntitySpecifics entity_specifics; 579 sync_pb::EntitySpecifics entity_specifics;
578 entity_specifics.MutableExtension(sync_pb::password)->CopyFrom(new_value); 580 entity_specifics.MutableExtension(sync_pb::password)->CopyFrom(new_value);
579 SetEntitySpecifics(entity_specifics); 581 SetEntitySpecifics(entity_specifics);
580 } 582 }
581 583
582 void WriteNode::SetThemeSpecifics( 584 void WriteNode::SetThemeSpecifics(
583 const sync_pb::ThemeSpecifics& new_value) { 585 const sync_pb::ThemeSpecifics& new_value) {
584 sync_pb::EntitySpecifics entity_specifics; 586 sync_pb::EntitySpecifics entity_specifics;
(...skipping 611 matching lines...) Expand 10 before | Expand all | Expand 10 after
1196 1198
1197 // Called when the user disables or enables a sync type. 1199 // Called when the user disables or enables a sync type.
1198 void UpdateEnabledTypes(); 1200 void UpdateEnabledTypes();
1199 1201
1200 // Tell the sync engine to start the syncing process. 1202 // Tell the sync engine to start the syncing process.
1201 void StartSyncingNormally(); 1203 void StartSyncingNormally();
1202 1204
1203 // Whether or not the Nigori node is encrypted using an explicit passphrase. 1205 // Whether or not the Nigori node is encrypted using an explicit passphrase.
1204 bool IsUsingExplicitPassphrase(); 1206 bool IsUsingExplicitPassphrase();
1205 1207
1208 // Update the Cryptographer from the current nigori node.
1209 // Note: opens a transaction and can trigger an ON_PASSPHRASE_REQUIRED, so
1210 // should only be called after syncapi is fully initialized.
1211 // Returns true if cryptographer is ready, false otherwise.
1212 bool UpdateCryptographerFromNigori();
1213
1206 // Set the datatypes we want to encrypt and encrypt any nodes as necessary. 1214 // Set the datatypes we want to encrypt and encrypt any nodes as necessary.
1207 void EncryptDataTypes(const syncable::ModelTypeSet& encrypted_types); 1215 void EncryptDataTypes(const syncable::ModelTypeSet& encrypted_types);
1208 1216
1209 // Try to set the current passphrase to |passphrase|, and record whether 1217 // Try to set the current passphrase to |passphrase|, and record whether
1210 // it is an explicit passphrase or implicitly using gaia in the Nigori 1218 // it is an explicit passphrase or implicitly using gaia in the Nigori
1211 // node. 1219 // node.
1212 void SetPassphrase(const std::string& passphrase, bool is_explicit); 1220 void SetPassphrase(const std::string& passphrase, bool is_explicit);
1213 1221
1214 // Call periodically from a database-safe thread to persist recent changes 1222 // Call periodically from a database-safe thread to persist recent changes
1215 // to the syncapi model. 1223 // to the syncapi model.
(...skipping 577 matching lines...) Expand 10 before | Expand all | Expand 10 after
1793 } 1801 }
1794 1802
1795 // Do this once the directory is opened. 1803 // Do this once the directory is opened.
1796 BootstrapEncryption(restored_key_for_bootstrapping); 1804 BootstrapEncryption(restored_key_for_bootstrapping);
1797 MarkAndNotifyInitializationComplete(); 1805 MarkAndNotifyInitializationComplete();
1798 return signed_in; 1806 return signed_in;
1799 } 1807 }
1800 1808
1801 void SyncManager::SyncInternal::BootstrapEncryption( 1809 void SyncManager::SyncInternal::BootstrapEncryption(
1802 const std::string& restored_key_for_bootstrapping) { 1810 const std::string& restored_key_for_bootstrapping) {
1811 // Cryptographer should only be accessed while holding a transaction.
1812 ReadTransaction trans(GetUserShare());
1813 Cryptographer* cryptographer = trans.GetCryptographer();
1814
1815 // Set the bootstrap token before bailing out if nigori node is not there.
1816 // This could happen if server asked us to migrate nigri.
1817 cryptographer->Bootstrap(restored_key_for_bootstrapping);
1818 }
1819
1820 bool SyncManager::SyncInternal::UpdateCryptographerFromNigori() {
1803 syncable::ScopedDirLookup lookup(dir_manager(), username_for_share()); 1821 syncable::ScopedDirLookup lookup(dir_manager(), username_for_share());
1804 if (!lookup.good()) { 1822 if (!lookup.good()) {
1805 LOG(INFO) << "BootstrapEncryption: lookup not good so bailing out"; 1823 NOTREACHED() << "BootstrapEncryption: lookup not good so bailing out";
1824 return false;
1825 }
1826 if (!lookup->initial_sync_ended_for_type(syncable::NIGORI))
1827 return false; // Should only happen during first time sync.
1828
1829 ReadTransaction trans(GetUserShare());
1830 Cryptographer* cryptographer = trans.GetCryptographer();
1831
1832 ReadNode node(&trans);
1833 if (!node.InitByTagLookup(kNigoriTag)) {
1806 NOTREACHED(); 1834 NOTREACHED();
1807 return; 1835 return false;
1836 }
1837 Cryptographer::UpdateResult result =
1838 cryptographer->Update(node.GetNigoriSpecifics());
1839 if (result == Cryptographer::NEEDS_PASSPHRASE) {
1840 ObserverList<SyncManager::Observer> temp_obs_list;
1841 CopyObservers(&temp_obs_list);
1842 FOR_EACH_OBSERVER(SyncManager::Observer, temp_obs_list,
1843 OnPassphraseRequired(sync_api::REASON_DECRYPTION));
1808 } 1844 }
1809 1845
1810 sync_pb::NigoriSpecifics nigori; 1846 return cryptographer->is_ready();
1811 syncable::ModelTypeSet encrypted_types;
1812 {
1813 // Cryptographer should only be accessed while holding a transaction.
1814 ReadTransaction trans(GetUserShare());
1815 Cryptographer* cryptographer = trans.GetCryptographer();
1816
1817 // Set the bootstrap token before bailing out if nigori node is not there.
1818 // This could happen if server asked us to migrate nigri.
1819 cryptographer->Bootstrap(restored_key_for_bootstrapping);
1820
1821 if (!lookup->initial_sync_ended_for_type(syncable::NIGORI))
1822 return;
1823
1824 ReadNode node(&trans);
1825 if (!node.InitByTagLookup(kNigoriTag)) {
1826 NOTREACHED();
1827 return;
1828 }
1829
1830 nigori.CopyFrom(node.GetNigoriSpecifics());
1831 Cryptographer::UpdateResult result = cryptographer->Update(nigori);
1832 if (result == Cryptographer::NEEDS_PASSPHRASE) {
1833 ObserverList<SyncManager::Observer> temp_obs_list;
1834 CopyObservers(&temp_obs_list);
1835 FOR_EACH_OBSERVER(SyncManager::Observer, temp_obs_list,
1836 OnPassphraseRequired(sync_api::REASON_DECRYPTION));
1837 }
1838
1839 // Refresh list of encrypted datatypes.
1840 encrypted_types = GetEncryptedTypes(&trans);
1841 }
1842
1843
1844
1845 // Ensure any datatypes that need encryption are encrypted.
1846 EncryptDataTypes(encrypted_types);
1847 } 1847 }
1848 1848
1849 void SyncManager::SyncInternal::StartSyncingNormally() { 1849 void SyncManager::SyncInternal::StartSyncingNormally() {
1850 // Start the sync scheduler. This won't actually result in any 1850 // Start the sync scheduler. This won't actually result in any
1851 // syncing until at least the DirectoryManager broadcasts the OPENED 1851 // syncing until at least the DirectoryManager broadcasts the OPENED
1852 // event, and a valid server connection is detected. 1852 // event, and a valid server connection is detected.
1853 if (scheduler()) // NULL during certain unittests. 1853 if (scheduler()) // NULL during certain unittests.
1854 scheduler()->Start(SyncScheduler::NORMAL_MODE, NULL); 1854 scheduler()->Start(SyncScheduler::NORMAL_MODE, NULL);
1855 } 1855 }
1856 1856
(...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after
2082 } 2082 }
2083 2083
2084 void SyncManager::SyncInternal::EncryptDataTypes( 2084 void SyncManager::SyncInternal::EncryptDataTypes(
2085 const syncable::ModelTypeSet& encrypted_types) { 2085 const syncable::ModelTypeSet& encrypted_types) {
2086 VLOG(1) << "Attempting to encrypt datatypes " 2086 VLOG(1) << "Attempting to encrypt datatypes "
2087 << syncable::ModelTypeSetToString(encrypted_types); 2087 << syncable::ModelTypeSetToString(encrypted_types);
2088 2088
2089 WriteTransaction trans(GetUserShare()); 2089 WriteTransaction trans(GetUserShare());
2090 WriteNode node(&trans); 2090 WriteNode node(&trans);
2091 if (!node.InitByTagLookup(kNigoriTag)) { 2091 if (!node.InitByTagLookup(kNigoriTag)) {
2092 LOG(ERROR) << "Unable to set encrypted datatypes because Nigori node not " 2092 NOTREACHED() << "Unable to set encrypted datatypes because Nigori node not "
2093 << "found."; 2093 << "found.";
2094 NOTREACHED();
2095 return; 2094 return;
2096 } 2095 }
2097 2096
2098 Cryptographer* cryptographer = trans.GetCryptographer(); 2097 Cryptographer* cryptographer = trans.GetCryptographer();
2099 2098
2099 if (!cryptographer->is_initialized()) {
2100 NOTREACHED() << "Attempting to encrypt datatypes when cryptographer not "
2101 << "initialized.";
2102 return;
2103 }
2104
2100 // Update the Nigori node set of encrypted datatypes so other machines notice. 2105 // Update the Nigori node set of encrypted datatypes so other machines notice.
2101 // Note, we merge the current encrypted types with those requested. Once a 2106 // Note, we merge the current encrypted types with those requested. Once a
2102 // datatypes is marked as needing encryption, it is never unmarked. 2107 // datatypes is marked as needing encryption, it is never unmarked.
2103 sync_pb::NigoriSpecifics nigori; 2108 sync_pb::NigoriSpecifics nigori;
2104 nigori.CopyFrom(node.GetNigoriSpecifics()); 2109 nigori.CopyFrom(node.GetNigoriSpecifics());
2105 syncable::ModelTypeSet current_encrypted_types = GetEncryptedTypes(&trans); 2110 syncable::ModelTypeSet current_encrypted_types = GetEncryptedTypes(&trans);
2106 syncable::ModelTypeSet newly_encrypted_types; 2111 syncable::ModelTypeSet newly_encrypted_types;
2107 std::set_union(current_encrypted_types.begin(), current_encrypted_types.end(), 2112 std::set_union(current_encrypted_types.begin(), current_encrypted_types.end(),
2108 encrypted_types.begin(), encrypted_types.end(), 2113 encrypted_types.begin(), encrypted_types.end(),
2109 std::inserter(newly_encrypted_types, 2114 std::inserter(newly_encrypted_types,
(...skipping 885 matching lines...) Expand 10 before | Expand all | Expand 10 after
2995 } 3000 }
2996 BaseTransaction::~BaseTransaction() { 3001 BaseTransaction::~BaseTransaction() {
2997 delete lookup_; 3002 delete lookup_;
2998 } 3003 }
2999 3004
3000 UserShare* SyncManager::GetUserShare() const { 3005 UserShare* SyncManager::GetUserShare() const {
3001 DCHECK(data_->initialized()) << "GetUserShare requires initialization!"; 3006 DCHECK(data_->initialized()) << "GetUserShare requires initialization!";
3002 return data_->GetUserShare(); 3007 return data_->GetUserShare();
3003 } 3008 }
3004 3009
3010 void SyncManager::RefreshEncryption() {
3011 DCHECK(data_->initialized());
3012 if (data_->UpdateCryptographerFromNigori())
3013 data_->EncryptDataTypes(syncable::ModelTypeSet());
3014 }
3015
3005 syncable::ModelTypeSet SyncManager::GetEncryptedDataTypes() const { 3016 syncable::ModelTypeSet SyncManager::GetEncryptedDataTypes() const {
3006 sync_api::ReadTransaction trans(GetUserShare()); 3017 sync_api::ReadTransaction trans(GetUserShare());
3007 return GetEncryptedTypes(&trans); 3018 return GetEncryptedTypes(&trans);
3008 } 3019 }
3009 3020
3010
3011 bool SyncManager::HasUnsyncedItems() const { 3021 bool SyncManager::HasUnsyncedItems() const {
3012 sync_api::ReadTransaction trans(GetUserShare()); 3022 sync_api::ReadTransaction trans(GetUserShare());
3013 return (trans.GetWrappedTrans()->directory()->unsynced_entity_count() != 0); 3023 return (trans.GetWrappedTrans()->directory()->unsynced_entity_count() != 0);
3014 } 3024 }
3015 3025
3016 void SyncManager::LogUnsyncedItems(int level) const { 3026 void SyncManager::LogUnsyncedItems(int level) const {
3017 std::vector<int64> unsynced_handles; 3027 std::vector<int64> unsynced_handles;
3018 sync_api::ReadTransaction trans(GetUserShare()); 3028 sync_api::ReadTransaction trans(GetUserShare());
3019 trans.GetWrappedTrans()->directory()->GetUnsyncedMetaHandles( 3029 trans.GetWrappedTrans()->directory()->GetUnsyncedMetaHandles(
3020 trans.GetWrappedTrans(), &unsynced_handles); 3030 trans.GetWrappedTrans(), &unsynced_handles);
(...skipping 18 matching lines...) Expand all
3039 void SyncManager::TriggerOnIncomingNotificationForTest( 3049 void SyncManager::TriggerOnIncomingNotificationForTest(
3040 const syncable::ModelTypeBitSet& model_types) { 3050 const syncable::ModelTypeBitSet& model_types) {
3041 syncable::ModelTypePayloadMap model_types_with_payloads = 3051 syncable::ModelTypePayloadMap model_types_with_payloads =
3042 syncable::ModelTypePayloadMapFromBitSet(model_types, 3052 syncable::ModelTypePayloadMapFromBitSet(model_types,
3043 std::string()); 3053 std::string());
3044 3054
3045 data_->OnIncomingNotification(model_types_with_payloads); 3055 data_->OnIncomingNotification(model_types_with_payloads);
3046 } 3056 }
3047 3057
3048 } // namespace sync_api 3058 } // namespace sync_api
OLDNEW
« no previous file with comments | « chrome/browser/sync/engine/syncapi.h ('k') | chrome/browser/sync/engine/syncapi_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698