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

Side by Side Diff: sync/engine/apply_control_data_updates.cc

Issue 10905191: [Sync] Add keystore migration conflict support. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase Created 8 years, 3 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 | « no previous file | sync/engine/apply_control_data_updates_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) 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/engine/apply_control_data_updates.h" 5 #include "sync/engine/apply_control_data_updates.h"
6 6
7 #include "base/metrics/histogram.h" 7 #include "base/metrics/histogram.h"
8 #include "sync/engine/conflict_resolver.h" 8 #include "sync/engine/conflict_resolver.h"
9 #include "sync/engine/conflict_util.h" 9 #include "sync/engine/conflict_util.h"
10 #include "sync/engine/syncer_util.h" 10 #include "sync/engine/syncer_util.h"
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
50 50
51 // Mainly for unit tests. We should have a Nigori node by this point. 51 // Mainly for unit tests. We should have a Nigori node by this point.
52 if (!nigori_node.good()) { 52 if (!nigori_node.good()) {
53 return false; 53 return false;
54 } 54 }
55 55
56 if (!nigori_node.Get(IS_UNAPPLIED_UPDATE)) { 56 if (!nigori_node.Get(IS_UNAPPLIED_UPDATE)) {
57 return true; 57 return true;
58 } 58 }
59 59
60 // We apply the nigori update regardless of whether there's a conflict or
61 // not in order to preserve any new encrypted types or encryption keys.
60 const sync_pb::NigoriSpecifics& nigori = 62 const sync_pb::NigoriSpecifics& nigori =
61 nigori_node.Get(SERVER_SPECIFICS).nigori(); 63 nigori_node.Get(SERVER_SPECIFICS).nigori();
62 trans->directory()->GetNigoriHandler()->ApplyNigoriUpdate(nigori, trans); 64 trans->directory()->GetNigoriHandler()->ApplyNigoriUpdate(nigori, trans);
63 65
64 // Make sure any unsynced changes are properly encrypted as necessary. 66 // Make sure any unsynced changes are properly encrypted as necessary.
65 // We only perform this if the cryptographer is ready. If not, these are 67 // We only perform this if the cryptographer is ready. If not, these are
66 // re-encrypted at SetDecryptionPassphrase time (via ReEncryptEverything). 68 // re-encrypted at SetDecryptionPassphrase time (via ReEncryptEverything).
67 // This logic covers the case where the nigori update marked new datatypes 69 // This logic covers the case where the nigori update marked new datatypes
68 // for encryption, but didn't change the passphrase. 70 // for encryption, but didn't change the passphrase.
69 if (cryptographer->is_ready()) { 71 if (cryptographer->is_ready()) {
70 // Note that we don't bother to encrypt any data for which IS_UNSYNCED 72 // Note that we don't bother to encrypt any data for which IS_UNSYNCED
71 // == false here. The machine that turned on encryption should know about 73 // == false here. The machine that turned on encryption should know about
72 // and re-encrypt all synced data. It's possible it could get interrupted 74 // and re-encrypt all synced data. It's possible it could get interrupted
73 // during this process, but we currently reencrypt everything at startup 75 // during this process, but we currently reencrypt everything at startup
74 // as well, so as soon as a client is restarted with this datatype marked 76 // as well, so as soon as a client is restarted with this datatype marked
75 // for encryption, all the data should be updated as necessary. 77 // for encryption, all the data should be updated as necessary.
76 78
77 // If this fails, something is wrong with the cryptographer, but there's 79 // If this fails, something is wrong with the cryptographer, but there's
78 // nothing we can do about it here. 80 // nothing we can do about it here.
79 DVLOG(1) << "Received new nigori, encrypting unsynced changes."; 81 DVLOG(1) << "Received new nigori, encrypting unsynced changes.";
80 syncable::ProcessUnsyncedChangesForEncryption(trans); 82 syncable::ProcessUnsyncedChangesForEncryption(trans);
81 } 83 }
82 84
83 if (!nigori_node.Get(IS_UNSYNCED)) { // Update only. 85 if (!nigori_node.Get(IS_UNSYNCED)) { // Update only.
84 UpdateLocalDataFromServerData(trans, &nigori_node); 86 UpdateLocalDataFromServerData(trans, &nigori_node);
85 } else { // Conflict. 87 } else { // Conflict.
86 // Create a new set of specifics based on the server specifics (which 88 const sync_pb::EntitySpecifics& server_specifics =
87 // preserves their encryption keys). 89 nigori_node.Get(SERVER_SPECIFICS);
88 sync_pb::EntitySpecifics specifics = nigori_node.Get(SERVER_SPECIFICS); 90 const sync_pb::NigoriSpecifics& server_nigori = server_specifics.nigori();
89 sync_pb::NigoriSpecifics* server_nigori = specifics.mutable_nigori(); 91 const sync_pb::EntitySpecifics& local_specifics =
90 // Store the merged set of encrypted types. 92 nigori_node.Get(SPECIFICS);
91 // (NigoriHandler::ApplyNigoriUpdate(..) will have merged the local types 93 const sync_pb::NigoriSpecifics& local_nigori = local_specifics.nigori();
92 // already). 94
95 // We initialize the new nigori with the server state, and will override
96 // it as necessary below.
97 sync_pb::EntitySpecifics new_specifics = nigori_node.Get(SERVER_SPECIFICS);
98 sync_pb::NigoriSpecifics* new_nigori = new_specifics.mutable_nigori();
99
100 // If the cryptographer is not ready, another client set a new encryption
101 // passphrase. If we had migrated locally, we will re-migrate when the
102 // pending keys are provided. If we had set a new custom passphrase locally
103 // the user will have another chance to set a custom passphrase later
104 // (assuming they hadn't set a custom passphrase on the other client).
105 // Therefore, we only attempt to merge the nigori nodes if the cryptographer
106 // is ready.
107 // Note: we only update the encryption keybag if we're sure that we aren't
108 // invalidating the keystore_decryptor_token (i.e. we're either
109 // not migrated or we copying over all local state).
110 if (cryptographer->is_ready()) {
111 if (local_nigori.has_passphrase_type() &&
112 server_nigori.has_passphrase_type()) {
113 // They're both migrated, preserve the local nigori if the passphrase
114 // type is more conservative.
115 if (server_nigori.passphrase_type() ==
116 sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE &&
117 local_nigori.passphrase_type() !=
118 sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE) {
119 DCHECK(local_nigori.passphrase_type() ==
120 sync_pb::NigoriSpecifics::FROZEN_IMPLICIT_PASSPHRASE ||
121 local_nigori.passphrase_type() ==
122 sync_pb::NigoriSpecifics::CUSTOM_PASSPHRASE);
123 new_nigori->CopyFrom(local_nigori);
124 cryptographer->GetKeys(new_nigori->mutable_encryption_keybag());
125 }
126 } else if (!local_nigori.has_passphrase_type() &&
127 !server_nigori.has_passphrase_type()) {
128 // Set the explicit passphrase based on the local state. If the server
129 // had set an explict passphrase, we should have pending keys, so
130 // should not reach this code.
131 // Because neither side is migrated, we don't have to worry about the
132 // keystore decryptor token.
133 new_nigori->set_keybag_is_frozen(local_nigori.keybag_is_frozen());
134 cryptographer->GetKeys(new_nigori->mutable_encryption_keybag());
135 } else if (local_nigori.has_passphrase_type()) {
136 // Local is migrated but server is not. Copy over the local migrated
137 // data.
138 new_nigori->CopyFrom(local_nigori);
139 cryptographer->GetKeys(new_nigori->mutable_encryption_keybag());
140 } // else leave the new nigori with the server state.
141 }
142
143 // Always update to the safest set of encrypted types.
93 trans->directory()->GetNigoriHandler()->UpdateNigoriFromEncryptedTypes( 144 trans->directory()->GetNigoriHandler()->UpdateNigoriFromEncryptedTypes(
94 server_nigori, 145 new_nigori,
95 trans); 146 trans);
96 // The cryptographer has the both the local and remote encryption keys 147
97 // (added at NigoriHandler::ApplyNigoriUpdate(..) time). 148 nigori_node.Put(SPECIFICS, new_specifics);
98 // If the cryptographer is ready, then it already merged both sets of keys
99 // and we can store them back in. In that case, the remote key was already
100 // part of the local keybag, so we preserve the local key as the default
101 // (including whether it's an explicit key).
102 // If the cryptographer is not ready, then the user will have to provide
103 // the passphrase to decrypt the pending keys. When they do so, the
104 // SetDecryptionPassphrase code will act based on whether the server
105 // update has an explicit passphrase or not.
106 // - If the server had an explicit passphrase, that explicit passphrase
107 // will be preserved as the default encryption key.
108 // - If the server did not have an explicit passphrase, we assume the
109 // local passphrase is the most up to date and preserve the local
110 // default encryption key marked as an implicit passphrase.
111 // This works fine except for the case where we had locally set an
112 // explicit passphrase. In that case the nigori node will have the default
113 // key based on the local explicit passphassphrase, but will not have it
114 // marked as explicit. To fix this we'd have to track whether we have a
115 // explicit passphrase or not separate from the nigori, which would
116 // introduce even more complexity, so we leave it up to the user to reset
117 // that passphrase as an explicit one via settings. The goal here is to
118 // ensure both sets of encryption keys are preserved.
119 if (cryptographer->is_ready()) {
120 cryptographer->GetKeys(server_nigori->mutable_encryption_keybag());
121 server_nigori->set_keybag_is_frozen(
122 nigori_node.Get(SPECIFICS).nigori().keybag_is_frozen());
123 }
124 nigori_node.Put(SPECIFICS, specifics);
125 DVLOG(1) << "Resolving simple conflict, merging nigori nodes: " 149 DVLOG(1) << "Resolving simple conflict, merging nigori nodes: "
126 << nigori_node; 150 << nigori_node;
127 151
128 OverwriteServerChanges(&nigori_node); 152 OverwriteServerChanges(&nigori_node);
129 153
130 UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict", 154 UMA_HISTOGRAM_ENUMERATION("Sync.ResolveSimpleConflict",
131 ConflictResolver::NIGORI_MERGE, 155 ConflictResolver::NIGORI_MERGE,
132 ConflictResolver::CONFLICT_RESOLUTION_SIZE); 156 ConflictResolver::CONFLICT_RESOLUTION_SIZE);
133 } 157 }
134 158
135 return true; 159 return true;
136 } 160 }
137 161
138 } // namespace syncer 162 } // namespace syncer
OLDNEW
« no previous file with comments | « no previous file | sync/engine/apply_control_data_updates_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698