Chromium Code Reviews| 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/time.h" | |
| 12 #include "base/tracked_objects.h" | 13 #include "base/tracked_objects.h" |
| 13 #include "base/metrics/histogram.h" | 14 #include "base/metrics/histogram.h" |
| 14 #include "sync/internal_api/public/read_node.h" | 15 #include "sync/internal_api/public/read_node.h" |
| 15 #include "sync/internal_api/public/read_transaction.h" | 16 #include "sync/internal_api/public/read_transaction.h" |
| 16 #include "sync/internal_api/public/user_share.h" | 17 #include "sync/internal_api/public/user_share.h" |
| 17 #include "sync/internal_api/public/util/experiments.h" | 18 #include "sync/internal_api/public/util/experiments.h" |
| 18 #include "sync/internal_api/public/write_node.h" | 19 #include "sync/internal_api/public/write_node.h" |
| 19 #include "sync/internal_api/public/write_transaction.h" | 20 #include "sync/internal_api/public/write_transaction.h" |
| 21 #include "sync/internal_api/public/util/sync_string_conversions.h" | |
| 20 #include "sync/protocol/encryption.pb.h" | 22 #include "sync/protocol/encryption.pb.h" |
| 21 #include "sync/protocol/nigori_specifics.pb.h" | 23 #include "sync/protocol/nigori_specifics.pb.h" |
| 22 #include "sync/protocol/sync.pb.h" | 24 #include "sync/protocol/sync.pb.h" |
| 23 #include "sync/syncable/base_transaction.h" | 25 #include "sync/syncable/base_transaction.h" |
| 24 #include "sync/syncable/directory.h" | 26 #include "sync/syncable/directory.h" |
| 25 #include "sync/syncable/entry.h" | 27 #include "sync/syncable/entry.h" |
| 26 #include "sync/syncable/nigori_util.h" | 28 #include "sync/syncable/nigori_util.h" |
| 27 #include "sync/util/cryptographer.h" | 29 #include "sync/util/cryptographer.h" |
| 30 #include "sync/util/time.h" | |
| 28 | 31 |
| 29 namespace syncer { | 32 namespace syncer { |
| 30 | 33 |
| 31 namespace { | 34 namespace { |
| 35 | |
| 32 // The maximum number of times we will automatically overwrite the nigori node | 36 // The maximum number of times we will automatically overwrite the nigori node |
| 33 // because the encryption keys don't match (per chrome instantiation). | 37 // because the encryption keys don't match (per chrome instantiation). |
| 34 // We protect ourselves against nigori rollbacks, but it's possible two | 38 // We protect ourselves against nigori rollbacks, but it's possible two |
| 35 // different clients might have contrasting view of what the nigori node state | 39 // different clients might have contrasting view of what the nigori node state |
| 36 // should be, in which case they might ping pong (see crbug.com/119207). | 40 // should be, in which case they might ping pong (see crbug.com/119207). |
| 37 static const int kNigoriOverwriteLimit = 10; | 41 static const int kNigoriOverwriteLimit = 10; |
| 42 | |
| 43 // The new passphrase state is sufficient to determine whether a nigori node | |
| 44 // is migrated to support keystore encryption. In addition though, we also | |
| 45 // want to verify the conditions for proper keystore encryption functionality. | |
| 46 // 1. Passphrase state is set. | |
| 47 // 2. Migration time is set. | |
| 48 // 3. Frozen keybag is true | |
| 49 // 4. If passphrase state is keystore, keystore_bootstrap_key is set. | |
| 50 bool IsNigoriMigratedToKeystore(const sync_pb::NigoriSpecifics& nigori) { | |
| 51 if (!nigori.has_passphrase_state()) | |
| 52 return false; | |
| 53 if (!nigori.has_keystore_migration_time()) | |
| 54 return false; | |
| 55 if (!nigori.frozen_keybag()) | |
| 56 return false; | |
| 57 if (nigori.passphrase_state() == | |
| 58 sync_pb::NigoriSpecifics::IMPLICIT_PASSPHRASE) | |
| 59 return false; | |
| 60 if (nigori.passphrase_state() == | |
| 61 sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE && | |
| 62 nigori.keystore_bootstrap().blob().empty()) | |
| 63 return false; | |
| 64 return true; | |
| 38 } | 65 } |
| 39 | 66 |
| 67 PassphraseState ProtoPassphraseStateToEnum( | |
| 68 sync_pb::NigoriSpecifics::PassphraseState state) { | |
| 69 switch(state) { | |
| 70 case sync_pb::NigoriSpecifics::IMPLICIT_PASSPHRASE: | |
| 71 return IMPLICIT_PASSPHRASE; | |
| 72 case sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE: | |
| 73 return KEYSTORE_PASSPHRASE; | |
| 74 case sync_pb::NigoriSpecifics::CUSTOM_PASSPHRASE: | |
| 75 return CUSTOM_PASSPHRASE; | |
| 76 case sync_pb::NigoriSpecifics::FROZEN_IMPLICIT_PASSPHRASE: | |
| 77 return FROZEN_IMPLICIT_PASSPHRASE; | |
| 78 default: | |
| 79 NOTREACHED(); | |
| 80 return IMPLICIT_PASSPHRASE; | |
| 81 }; | |
| 82 } | |
| 83 | |
| 84 sync_pb::NigoriSpecifics::PassphraseState | |
| 85 EnumPassphraseStateToProto(PassphraseState state) { | |
| 86 switch(state) { | |
| 87 case IMPLICIT_PASSPHRASE: | |
| 88 return sync_pb::NigoriSpecifics::IMPLICIT_PASSPHRASE; | |
| 89 case KEYSTORE_PASSPHRASE: | |
| 90 return sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE; | |
| 91 case CUSTOM_PASSPHRASE: | |
| 92 return sync_pb::NigoriSpecifics::CUSTOM_PASSPHRASE; | |
| 93 case FROZEN_IMPLICIT_PASSPHRASE: | |
| 94 return sync_pb::NigoriSpecifics::FROZEN_IMPLICIT_PASSPHRASE; | |
| 95 default: | |
| 96 NOTREACHED(); | |
| 97 return sync_pb::NigoriSpecifics::IMPLICIT_PASSPHRASE;; | |
| 98 }; | |
| 99 } | |
| 100 | |
| 101 bool IsExplicitPassphrase(PassphraseState state) { | |
| 102 return state == CUSTOM_PASSPHRASE || state == FROZEN_IMPLICIT_PASSPHRASE; | |
| 103 } | |
| 104 | |
| 105 } // namespace | |
| 106 | |
| 40 SyncEncryptionHandlerImpl::Vault::Vault( | 107 SyncEncryptionHandlerImpl::Vault::Vault( |
| 41 Encryptor* encryptor, | 108 Encryptor* encryptor, |
| 42 ModelTypeSet encrypted_types) | 109 ModelTypeSet encrypted_types) |
| 43 : cryptographer(encryptor), | 110 : cryptographer(encryptor), |
| 44 encrypted_types(encrypted_types) { | 111 encrypted_types(encrypted_types) { |
| 45 } | 112 } |
| 46 | 113 |
| 47 SyncEncryptionHandlerImpl::Vault::~Vault() { | 114 SyncEncryptionHandlerImpl::Vault::~Vault() { |
| 48 } | 115 } |
| 49 | 116 |
| 50 SyncEncryptionHandlerImpl::SyncEncryptionHandlerImpl( | 117 SyncEncryptionHandlerImpl::SyncEncryptionHandlerImpl( |
| 51 UserShare* user_share, | 118 UserShare* user_share, |
| 52 Encryptor* encryptor, | 119 Encryptor* encryptor, |
| 53 const std::string& restored_key_for_bootstrapping, | 120 const std::string& restored_key_for_bootstrapping, |
| 54 const std::string& restored_keystore_key_for_bootstrapping) | 121 const std::string& restored_keystore_key_for_bootstrapping) |
| 55 : weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), | 122 : weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)), |
| 56 user_share_(user_share), | 123 user_share_(user_share), |
| 57 vault_unsafe_(encryptor, SensitiveTypes()), | 124 vault_unsafe_(encryptor, SensitiveTypes()), |
| 58 encrypt_everything_(false), | 125 encrypt_everything_(false), |
| 59 passphrase_state_(IMPLICIT_PASSPHRASE), | 126 passphrase_state_(IMPLICIT_PASSPHRASE), |
| 60 keystore_key_(restored_keystore_key_for_bootstrapping), | 127 keystore_key_(restored_keystore_key_for_bootstrapping), |
| 61 nigori_overwrite_count_(0) { | 128 nigori_overwrite_count_(0), |
| 129 migration_time_ms_(0) { | |
| 62 // We only bootstrap the user provided passphrase. The keystore key is handled | 130 // We only bootstrap the user provided passphrase. The keystore key is handled |
| 63 // at Init time once we're sure the nigori is downloaded. | 131 // at Init time once we're sure the nigori is downloaded. |
| 64 vault_unsafe_.cryptographer.Bootstrap(restored_key_for_bootstrapping); | 132 vault_unsafe_.cryptographer.Bootstrap(restored_key_for_bootstrapping); |
| 65 } | 133 } |
| 66 | 134 |
| 67 SyncEncryptionHandlerImpl::~SyncEncryptionHandlerImpl() {} | 135 SyncEncryptionHandlerImpl::~SyncEncryptionHandlerImpl() {} |
| 68 | 136 |
| 69 void SyncEncryptionHandlerImpl::AddObserver(Observer* observer) { | 137 void SyncEncryptionHandlerImpl::AddObserver(Observer* observer) { |
| 70 DCHECK(thread_checker_.CalledOnValidThread()); | 138 DCHECK(thread_checker_.CalledOnValidThread()); |
| 71 DCHECK(!observers_.HasObserver(observer)); | 139 DCHECK(!observers_.HasObserver(observer)); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 123 | 191 |
| 124 // All accesses to the cryptographer are protected by a transaction. | 192 // All accesses to the cryptographer are protected by a transaction. |
| 125 WriteTransaction trans(FROM_HERE, user_share_); | 193 WriteTransaction trans(FROM_HERE, user_share_); |
| 126 KeyParams key_params = {"localhost", "dummy", passphrase}; | 194 KeyParams key_params = {"localhost", "dummy", passphrase}; |
| 127 WriteNode node(&trans); | 195 WriteNode node(&trans); |
| 128 if (node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK) { | 196 if (node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK) { |
| 129 NOTREACHED(); | 197 NOTREACHED(); |
| 130 return; | 198 return; |
| 131 } | 199 } |
| 132 | 200 |
| 133 bool nigori_has_explicit_passphrase = | 201 Cryptographer* cryptographer = |
| 134 node.GetNigoriSpecifics().using_explicit_passphrase(); | 202 &UnlockVaultMutable(trans.GetWrappedTrans())->cryptographer; |
| 203 | |
| 204 // Once we've migrated to keystore, the only way to set a passphrase for | |
| 205 // encryption is to set a custom passphrase. | |
| 206 if (IsNigoriMigratedToKeystore(node.GetNigoriSpecifics())) { | |
| 207 if (!is_explicit) { | |
| 208 DCHECK(cryptographer->is_ready()); | |
| 209 // The user is setting a new implicit passphrase. At this point we don't | |
| 210 // care, so drop it on the floor. This is safe because if we have a | |
| 211 // migrated nigori node, then we must at least have pending keys, and | |
|
tim (not reviewing)
2012/09/06 01:04:20
This confused me a bit. If we had pending keys, w
Nicolas Zea
2012/09/06 21:45:27
Done.
| |
| 212 // therefore this is just the client attempting to update the gaia | |
| 213 // passphrase. | |
| 214 LOG(WARNING) << "Ignoring new implicit passphrase. Keystore migration " | |
| 215 << "already performed."; | |
| 216 return; | |
| 217 } | |
| 218 SetCustomPassphrase(passphrase, &trans, &node); | |
|
tim (not reviewing)
2012/09/06 01:04:20
Add comment (or cleverly rename) that this is tent
Nicolas Zea
2012/09/06 21:45:27
Done.
| |
| 219 return; | |
| 220 } | |
| 221 | |
| 135 std::string bootstrap_token; | 222 std::string bootstrap_token; |
| 136 sync_pb::EncryptedData pending_keys; | 223 sync_pb::EncryptedData pending_keys; |
| 137 Cryptographer* cryptographer = | |
| 138 &UnlockVaultMutable(trans.GetWrappedTrans())->cryptographer; | |
| 139 if (cryptographer->has_pending_keys()) | 224 if (cryptographer->has_pending_keys()) |
| 140 pending_keys = cryptographer->GetPendingKeys(); | 225 pending_keys = cryptographer->GetPendingKeys(); |
| 141 bool success = false; | 226 bool success = false; |
| 142 | 227 |
| 143 // There are six cases to handle here: | 228 // There are six cases to handle here: |
| 144 // 1. The user has no pending keys and is setting their current GAIA password | 229 // 1. The user has no pending keys and is setting their current GAIA password |
| 145 // as the encryption passphrase. This happens either during first time sync | 230 // as the encryption passphrase. This happens either during first time sync |
| 146 // with a clean profile, or after re-authenticating on a profile that was | 231 // with a clean profile, or after re-authenticating on a profile that was |
| 147 // already signed in with the cryptographer ready. | 232 // already signed in with the cryptographer ready. |
| 148 // 2. The user has no pending keys, and is overwriting an (already provided) | 233 // 2. The user has no pending keys, and is overwriting an (already provided) |
| 149 // implicit passphrase with an explicit (custom) passphrase. | 234 // implicit passphrase with an explicit (custom) passphrase. |
| 150 // 3. The user has pending keys for an explicit passphrase that is somehow set | 235 // 3. The user has pending keys for an explicit passphrase that is somehow set |
| 151 // to their current GAIA passphrase. | 236 // to their current GAIA passphrase. |
| 152 // 4. The user has pending keys encrypted with their current GAIA passphrase | 237 // 4. The user has pending keys encrypted with their current GAIA passphrase |
| 153 // and the caller passes in the current GAIA passphrase. | 238 // and the caller passes in the current GAIA passphrase. |
| 154 // 5. The user has pending keys encrypted with an older GAIA passphrase | 239 // 5. The user has pending keys encrypted with an older GAIA passphrase |
| 155 // and the caller passes in the current GAIA passphrase. | 240 // and the caller passes in the current GAIA passphrase. |
| 156 // 6. The user has previously done encryption with an explicit passphrase. | 241 // 6. The user has previously done encryption with an explicit passphrase. |
| 157 // Furthermore, we enforce the fact that the bootstrap encryption token will | 242 // Furthermore, we enforce the fact that the bootstrap encryption token will |
| 158 // always be derived from the newest GAIA password if the account is using | 243 // always be derived from the newest GAIA password if the account is using |
| 159 // an implicit passphrase (even if the data is encrypted with an old GAIA | 244 // an implicit passphrase (even if the data is encrypted with an old GAIA |
| 160 // password). If the account is using an explicit (custom) passphrase, the | 245 // password). If the account is using an explicit (custom) passphrase, the |
| 161 // bootstrap token will be derived from the most recently provided explicit | 246 // bootstrap token will be derived from the most recently provided explicit |
| 162 // passphrase (that was able to decrypt the data). | 247 // passphrase (that was able to decrypt the data). |
| 163 if (!nigori_has_explicit_passphrase) { | 248 if (!IsExplicitPassphrase(passphrase_state_)) { |
| 164 if (!cryptographer->has_pending_keys()) { | 249 if (!cryptographer->has_pending_keys()) { |
| 165 if (cryptographer->AddKey(key_params)) { | 250 if (cryptographer->AddKey(key_params)) { |
| 166 // Case 1 and 2. We set a new GAIA passphrase when there are no pending | 251 // Case 1 and 2. We set a new GAIA passphrase when there are no pending |
| 167 // keys (1), or overwriting an implicit passphrase with a new explicit | 252 // keys (1), or overwriting an implicit passphrase with a new explicit |
| 168 // one (2) when there are no pending keys. | 253 // one (2) when there are no pending keys. |
| 169 DVLOG(1) << "Setting " << (is_explicit ? "explicit" : "implicit" ) | 254 if (is_explicit) { |
| 170 << " passphrase for encryption."; | 255 DVLOG(1) << "Setting explicit passphrase for encryption."; |
| 256 passphrase_state_ = CUSTOM_PASSPHRASE; | |
| 257 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, | |
| 258 OnPassphraseStateChanged(passphrase_state_)); | |
| 259 } else { | |
| 260 DVLOG(1) << "Setting implicit passphrase for encryption."; | |
| 261 } | |
| 171 cryptographer->GetBootstrapToken(&bootstrap_token); | 262 cryptographer->GetBootstrapToken(&bootstrap_token); |
| 172 success = true; | 263 success = true; |
| 173 } else { | 264 } else { |
| 174 NOTREACHED() << "Failed to add key to cryptographer."; | 265 NOTREACHED() << "Failed to add key to cryptographer."; |
| 175 success = false; | 266 success = false; |
| 176 } | 267 } |
| 177 } else { // cryptographer->has_pending_keys() == true | 268 } else { // cryptographer->has_pending_keys() == true |
| 178 if (is_explicit) { | 269 if (is_explicit) { |
| 179 // This can only happen if the nigori node is updated with a new | 270 // This can only happen if the nigori node is updated with a new |
| 180 // implicit passphrase while a client is attempting to set a new custom | 271 // implicit passphrase while a client is attempting to set a new custom |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 202 temp_cryptographer.GetBootstrapToken(&bootstrap_token); | 293 temp_cryptographer.GetBootstrapToken(&bootstrap_token); |
| 203 // We then set the new passphrase as the default passphrase of the | 294 // We then set the new passphrase as the default passphrase of the |
| 204 // real cryptographer, even though we have pending keys. This is safe, | 295 // real cryptographer, even though we have pending keys. This is safe, |
| 205 // as although Cryptographer::is_initialized() will now be true, | 296 // as although Cryptographer::is_initialized() will now be true, |
| 206 // is_ready() will remain false due to having pending keys. | 297 // is_ready() will remain false due to having pending keys. |
| 207 cryptographer->AddKey(key_params); | 298 cryptographer->AddKey(key_params); |
| 208 success = false; | 299 success = false; |
| 209 } | 300 } |
| 210 } // is_explicit | 301 } // is_explicit |
| 211 } // cryptographer->has_pending_keys() | 302 } // cryptographer->has_pending_keys() |
| 212 } else { // nigori_has_explicit_passphrase == true | 303 } else { // nigori_has_explicit_passphrase == true |
|
tim (not reviewing)
2012/09/06 01:04:20
update this comment to reflect the if.
Nicolas Zea
2012/09/06 21:45:27
Done.
| |
| 213 // Case 6. We do not want to override a previously set explicit passphrase, | 304 // Case 6. We do not want to override a previously set explicit passphrase, |
| 214 // so we return a failure. | 305 // so we return a failure. |
| 215 DVLOG(1) << "Failing because an explicit passphrase is already set."; | 306 DVLOG(1) << "Failing because an explicit passphrase is already set."; |
| 216 success = false; | 307 success = false; |
| 217 } | 308 } |
| 218 | 309 |
| 219 DVLOG_IF(1, !success) | 310 DVLOG_IF(1, !success) |
| 220 << "Failure in SetEncryptionPassphrase; notifying and returning."; | 311 << "Failure in SetEncryptionPassphrase; notifying and returning."; |
| 221 DVLOG_IF(1, success) | 312 DVLOG_IF(1, success) |
| 222 << "Successfully set encryption passphrase; updating nigori and " | 313 << "Successfully set encryption passphrase; updating nigori and " |
| 223 "reencrypting."; | 314 "reencrypting."; |
| 224 | 315 |
| 225 FinishSetPassphrase( | 316 FinishSetPassphrase(success, bootstrap_token, &trans, &node); |
| 226 success, bootstrap_token, is_explicit, &trans, &node); | |
| 227 } | 317 } |
| 228 | 318 |
| 229 void SyncEncryptionHandlerImpl::SetDecryptionPassphrase( | 319 void SyncEncryptionHandlerImpl::SetDecryptionPassphrase( |
| 230 const std::string& passphrase) { | 320 const std::string& passphrase) { |
| 231 DCHECK(thread_checker_.CalledOnValidThread()); | 321 DCHECK(thread_checker_.CalledOnValidThread()); |
| 232 // We do not accept empty passphrases. | 322 // We do not accept empty passphrases. |
| 233 if (passphrase.empty()) { | 323 if (passphrase.empty()) { |
| 234 NOTREACHED() << "Cannot decrypt with an empty passphrase."; | 324 NOTREACHED() << "Cannot decrypt with an empty passphrase."; |
| 235 return; | 325 return; |
| 236 } | 326 } |
| 237 | 327 |
| 238 // All accesses to the cryptographer are protected by a transaction. | 328 // All accesses to the cryptographer are protected by a transaction. |
| 239 WriteTransaction trans(FROM_HERE, user_share_); | 329 WriteTransaction trans(FROM_HERE, user_share_); |
| 240 KeyParams key_params = {"localhost", "dummy", passphrase}; | 330 KeyParams key_params = {"localhost", "dummy", passphrase}; |
| 241 WriteNode node(&trans); | 331 WriteNode node(&trans); |
| 242 if (node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK) { | 332 if (node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK) { |
| 243 NOTREACHED(); | 333 NOTREACHED(); |
| 244 return; | 334 return; |
| 245 } | 335 } |
| 246 | 336 |
| 337 // Once we've migrated to keystore, we're only ever decrypting an explicit | |
|
tim (not reviewing)
2012/09/06 01:04:20
nit - decrypting keys derived from an explicit pas
Nicolas Zea
2012/09/06 21:45:27
Done.
| |
| 338 // passphrase. But, for clients without a keystore key yet (either not on | |
| 339 // by default or failed to download one), we still support decrypting with | |
| 340 // a gaia passphrase, and therefore bypass the DecryptExplicitPassphrase | |
| 341 // logic. | |
| 342 if (IsNigoriMigratedToKeystore(node.GetNigoriSpecifics()) && | |
| 343 IsExplicitPassphrase(passphrase_state_)) { | |
| 344 DecryptExplicitPassphrase(passphrase, &trans, &node); | |
|
tim (not reviewing)
2012/09/06 01:04:20
nit - DecryptPendingExplicitPassphraseKeys ?
Nicolas Zea
2012/09/06 21:45:27
Done.
| |
| 345 return; | |
| 346 } | |
| 347 | |
| 247 Cryptographer* cryptographer = | 348 Cryptographer* cryptographer = |
| 248 &UnlockVaultMutable(trans.GetWrappedTrans())->cryptographer; | 349 &UnlockVaultMutable(trans.GetWrappedTrans())->cryptographer; |
| 249 if (!cryptographer->has_pending_keys()) { | 350 if (!cryptographer->has_pending_keys()) { |
| 250 // Note that this *can* happen in a rare situation where data is | 351 // Note that this *can* happen in a rare situation where data is |
| 251 // re-encrypted on another client while a SetDecryptionPassphrase() call is | 352 // re-encrypted on another client while a SetDecryptionPassphrase() call is |
| 252 // in-flight on this client. It is rare enough that we choose to do nothing. | 353 // in-flight on this client. It is rare enough that we choose to do nothing. |
| 253 NOTREACHED() << "Attempt to set decryption passphrase failed because there " | 354 NOTREACHED() << "Attempt to set decryption passphrase failed because there " |
| 254 << "were no pending keys."; | 355 << "were no pending keys."; |
| 255 return; | 356 return; |
| 256 } | 357 } |
| 257 | 358 |
| 258 bool nigori_has_explicit_passphrase = | |
| 259 node.GetNigoriSpecifics().using_explicit_passphrase(); | |
| 260 std::string bootstrap_token; | 359 std::string bootstrap_token; |
| 261 sync_pb::EncryptedData pending_keys; | 360 sync_pb::EncryptedData pending_keys; |
| 262 pending_keys = cryptographer->GetPendingKeys(); | 361 pending_keys = cryptographer->GetPendingKeys(); |
| 263 bool success = false; | 362 bool success = false; |
| 264 | 363 |
| 265 // There are three cases to handle here: | 364 // There are three cases to handle here: |
| 266 // 7. We're using the current GAIA password to decrypt the pending keys. This | 365 // 7. We're using the current GAIA password to decrypt the pending keys. This |
| 267 // happens when signing in to an account with a previously set implicit | 366 // happens when signing in to an account with a previously set implicit |
| 268 // passphrase, where the data is already encrypted with the newest GAIA | 367 // passphrase, where the data is already encrypted with the newest GAIA |
| 269 // password. | 368 // password. |
| 270 // 8. The user is providing an old GAIA password to decrypt the pending keys. | 369 // 8. The user is providing an old GAIA password to decrypt the pending keys. |
| 271 // In this case, the user is using an implicit passphrase, but has changed | 370 // In this case, the user is using an implicit passphrase, but has changed |
| 272 // their password since they last encrypted their data, and therefore | 371 // their password since they last encrypted their data, and therefore |
| 273 // their current GAIA password was unable to decrypt the data. This will | 372 // their current GAIA password was unable to decrypt the data. This will |
| 274 // happen when the user is setting up a new profile with a previously | 373 // happen when the user is setting up a new profile with a previously |
| 275 // encrypted account (after changing passwords). | 374 // encrypted account (after changing passwords). |
| 276 // 9. The user is providing a previously set explicit passphrase to decrypt | 375 // 9. The user is providing a previously set explicit passphrase to decrypt |
| 277 // the pending keys. | 376 // the pending keys. |
| 278 if (!nigori_has_explicit_passphrase) { | 377 if (!IsExplicitPassphrase(passphrase_state_)) { |
| 279 if (cryptographer->is_initialized()) { | 378 if (cryptographer->is_initialized()) { |
| 280 // We only want to change the default encryption key to the pending | 379 // We only want to change the default encryption key to the pending |
| 281 // one if the pending keybag already contains the current default. | 380 // one if the pending keybag already contains the current default. |
| 282 // This covers the case where a different client re-encrypted | 381 // This covers the case where a different client re-encrypted |
| 283 // everything with a newer gaia passphrase (and hence the keybag | 382 // everything with a newer gaia passphrase (and hence the keybag |
| 284 // contains keys from all previously used gaia passphrases). | 383 // contains keys from all previously used gaia passphrases). |
| 285 // Otherwise, we're in a situation where the pending keys are | 384 // Otherwise, we're in a situation where the pending keys are |
| 286 // encrypted with an old gaia passphrase, while the default is the | 385 // encrypted with an old gaia passphrase, while the default is the |
| 287 // current gaia passphrase. In that case, we preserve the default. | 386 // current gaia passphrase. In that case, we preserve the default. |
| 288 Cryptographer temp_cryptographer(cryptographer->encryptor()); | 387 Cryptographer temp_cryptographer(cryptographer->encryptor()); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 355 success = false; | 454 success = false; |
| 356 } | 455 } |
| 357 } // nigori_has_explicit_passphrase | 456 } // nigori_has_explicit_passphrase |
| 358 | 457 |
| 359 DVLOG_IF(1, !success) | 458 DVLOG_IF(1, !success) |
| 360 << "Failure in SetDecryptionPassphrase; notifying and returning."; | 459 << "Failure in SetDecryptionPassphrase; notifying and returning."; |
| 361 DVLOG_IF(1, success) | 460 DVLOG_IF(1, success) |
| 362 << "Successfully set decryption passphrase; updating nigori and " | 461 << "Successfully set decryption passphrase; updating nigori and " |
| 363 "reencrypting."; | 462 "reencrypting."; |
| 364 | 463 |
| 365 FinishSetPassphrase(success, | 464 FinishSetPassphrase(success, bootstrap_token, &trans, &node); |
| 366 bootstrap_token, | |
| 367 nigori_has_explicit_passphrase, | |
| 368 &trans, | |
| 369 &node); | |
| 370 } | 465 } |
| 371 | 466 |
| 372 void SyncEncryptionHandlerImpl::EnableEncryptEverything() { | 467 void SyncEncryptionHandlerImpl::EnableEncryptEverything() { |
| 373 DCHECK(thread_checker_.CalledOnValidThread()); | 468 DCHECK(thread_checker_.CalledOnValidThread()); |
| 374 WriteTransaction trans(FROM_HERE, user_share_); | 469 WriteTransaction trans(FROM_HERE, user_share_); |
| 375 ModelTypeSet* encrypted_types = | 470 DVLOG(1) << "Enabling encrypt everything."; |
| 376 &UnlockVaultMutable(trans.GetWrappedTrans())->encrypted_types; | 471 if (encrypt_everything_) |
| 377 if (encrypt_everything_) { | |
| 378 DCHECK(encrypted_types->Equals(ModelTypeSet::All())); | |
| 379 return; | 472 return; |
| 380 } | 473 EnableEncryptEverythingImpl(trans.GetWrappedTrans()); |
| 381 DVLOG(1) << "Enabling encrypt everything."; | |
| 382 encrypt_everything_ = true; | |
| 383 // Change |encrypted_types_| directly to avoid sending more than one | |
| 384 // notification. | |
| 385 *encrypted_types = ModelTypeSet::All(); | |
| 386 FOR_EACH_OBSERVER( | |
| 387 Observer, observers_, | |
| 388 OnEncryptedTypesChanged(*encrypted_types, encrypt_everything_)); | |
| 389 WriteEncryptionStateToNigori(&trans); | 474 WriteEncryptionStateToNigori(&trans); |
| 390 if (UnlockVault(trans.GetWrappedTrans()).cryptographer.is_ready()) | 475 if (UnlockVault(trans.GetWrappedTrans()).cryptographer.is_ready()) |
| 391 ReEncryptEverything(&trans); | 476 ReEncryptEverything(&trans); |
| 392 } | 477 } |
| 393 | 478 |
| 394 bool SyncEncryptionHandlerImpl::EncryptEverythingEnabled() const { | 479 bool SyncEncryptionHandlerImpl::EncryptEverythingEnabled() const { |
| 395 DCHECK(thread_checker_.CalledOnValidThread()); | 480 DCHECK(thread_checker_.CalledOnValidThread()); |
| 396 return encrypt_everything_; | 481 return encrypt_everything_; |
| 397 } | 482 } |
| 398 | 483 |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 418 FOR_EACH_OBSERVER( | 503 FOR_EACH_OBSERVER( |
| 419 SyncEncryptionHandler::Observer, | 504 SyncEncryptionHandler::Observer, |
| 420 observers_, | 505 observers_, |
| 421 OnCryptographerStateChanged( | 506 OnCryptographerStateChanged( |
| 422 &UnlockVaultMutable(trans)->cryptographer)); | 507 &UnlockVaultMutable(trans)->cryptographer)); |
| 423 } | 508 } |
| 424 | 509 |
| 425 void SyncEncryptionHandlerImpl::UpdateNigoriFromEncryptedTypes( | 510 void SyncEncryptionHandlerImpl::UpdateNigoriFromEncryptedTypes( |
| 426 sync_pb::NigoriSpecifics* nigori, | 511 sync_pb::NigoriSpecifics* nigori, |
| 427 syncable::BaseTransaction* const trans) const { | 512 syncable::BaseTransaction* const trans) const { |
| 513 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 428 syncable::UpdateNigoriFromEncryptedTypes(UnlockVault(trans).encrypted_types, | 514 syncable::UpdateNigoriFromEncryptedTypes(UnlockVault(trans).encrypted_types, |
| 429 encrypt_everything_, | 515 encrypt_everything_, |
| 430 nigori); | 516 nigori); |
| 431 } | 517 } |
| 432 | 518 |
| 433 bool SyncEncryptionHandlerImpl::NeedKeystoreKey( | 519 bool SyncEncryptionHandlerImpl::NeedKeystoreKey( |
| 434 syncable::BaseTransaction* const trans) const { | 520 syncable::BaseTransaction* const trans) const { |
| 521 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 435 return keystore_key_.empty(); | 522 return keystore_key_.empty(); |
| 436 } | 523 } |
| 437 | 524 |
| 438 bool SyncEncryptionHandlerImpl::SetKeystoreKey( | 525 bool SyncEncryptionHandlerImpl::SetKeystoreKey( |
| 439 const std::string& key, | 526 const std::string& key, |
| 440 syncable::BaseTransaction* const trans) { | 527 syncable::BaseTransaction* const trans) { |
| 528 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 441 if (!keystore_key_.empty() || key.empty()) | 529 if (!keystore_key_.empty() || key.empty()) |
| 442 return false; | 530 return false; |
| 443 keystore_key_ = key; | 531 keystore_key_ = key; |
| 444 | 532 |
| 445 // TODO(zea): trigger migration if necessary. | |
| 446 | |
| 447 DVLOG(1) << "Keystore bootstrap token updated."; | 533 DVLOG(1) << "Keystore bootstrap token updated."; |
| 448 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, | 534 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, |
| 449 OnBootstrapTokenUpdated(key, | 535 OnBootstrapTokenUpdated(key, |
| 450 KEYSTORE_BOOTSTRAP_TOKEN)); | 536 KEYSTORE_BOOTSTRAP_TOKEN)); |
| 537 | |
| 538 Cryptographer* cryptographer = &UnlockVaultMutable(trans)->cryptographer; | |
| 539 syncable::Entry entry(trans, syncable::GET_BY_SERVER_TAG, kNigoriTag); | |
| 540 if (entry.good()) { | |
| 541 const sync_pb::NigoriSpecifics& nigori = | |
| 542 entry.Get(syncable::SPECIFICS).nigori(); | |
| 543 if (cryptographer->has_pending_keys() && | |
| 544 IsNigoriMigratedToKeystore(nigori) && | |
| 545 !nigori.keystore_bootstrap().blob().empty()) { | |
| 546 // If the nigori is already migrated and we have pending keys, we might | |
| 547 // be able to decrypt them using the keystore bootstrap key. | |
| 548 DecryptPendingKeysWithKeystoreKey(keystore_key_, | |
| 549 nigori.keystore_bootstrap(), | |
| 550 cryptographer); | |
| 551 } else if (ShouldTriggerMigration(nigori, *cryptographer)) { | |
| 552 // We call rewrite nigori to attempt to trigger migration. | |
| 553 // Need to post a task to open a new sync_api transaction. | |
| 554 MessageLoop::current()->PostTask( | |
| 555 FROM_HERE, | |
| 556 base::Bind(&SyncEncryptionHandlerImpl::RewriteNigori, | |
| 557 weak_ptr_factory_.GetWeakPtr())); | |
| 558 } | |
| 559 } | |
| 560 | |
| 451 return true; | 561 return true; |
| 452 } | 562 } |
| 453 | 563 |
| 454 ModelTypeSet SyncEncryptionHandlerImpl::GetEncryptedTypes( | 564 ModelTypeSet SyncEncryptionHandlerImpl::GetEncryptedTypes( |
| 455 syncable::BaseTransaction* const trans) const { | 565 syncable::BaseTransaction* const trans) const { |
| 456 return UnlockVault(trans).encrypted_types; | 566 return UnlockVault(trans).encrypted_types; |
| 457 } | 567 } |
| 458 | 568 |
| 459 Cryptographer* SyncEncryptionHandlerImpl::GetCryptographerUnsafe() { | 569 Cryptographer* SyncEncryptionHandlerImpl::GetCryptographerUnsafe() { |
| 460 DCHECK(thread_checker_.CalledOnValidThread()); | 570 DCHECK(thread_checker_.CalledOnValidThread()); |
| 461 return &vault_unsafe_.cryptographer; | 571 return &vault_unsafe_.cryptographer; |
| 462 } | 572 } |
| 463 | 573 |
| 464 ModelTypeSet SyncEncryptionHandlerImpl::GetEncryptedTypesUnsafe() { | 574 ModelTypeSet SyncEncryptionHandlerImpl::GetEncryptedTypesUnsafe() { |
| 465 DCHECK(thread_checker_.CalledOnValidThread()); | 575 DCHECK(thread_checker_.CalledOnValidThread()); |
| 466 return vault_unsafe_.encrypted_types; | 576 return vault_unsafe_.encrypted_types; |
| 467 } | 577 } |
| 468 | 578 |
| 579 bool SyncEncryptionHandlerImpl::MigratedToKeystore() { | |
| 580 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 581 ReadTransaction trans(FROM_HERE, user_share_); | |
| 582 ReadNode nigori_node(&trans); | |
| 583 if (nigori_node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK) | |
| 584 return false; | |
| 585 return IsNigoriMigratedToKeystore(nigori_node.GetNigoriSpecifics()); | |
| 586 } | |
| 587 | |
| 469 // This function iterates over all encrypted types. There are many scenarios in | 588 // This function iterates over all encrypted types. There are many scenarios in |
| 470 // which data for some or all types is not currently available. In that case, | 589 // which data for some or all types is not currently available. In that case, |
| 471 // the lookup of the root node will fail and we will skip encryption for that | 590 // the lookup of the root node will fail and we will skip encryption for that |
| 472 // type. | 591 // type. |
| 473 void SyncEncryptionHandlerImpl::ReEncryptEverything( | 592 void SyncEncryptionHandlerImpl::ReEncryptEverything( |
| 474 WriteTransaction* trans) { | 593 WriteTransaction* trans) { |
| 475 DCHECK(thread_checker_.CalledOnValidThread()); | 594 DCHECK(thread_checker_.CalledOnValidThread()); |
| 476 DCHECK(UnlockVault(trans->GetWrappedTrans()).cryptographer.is_ready()); | 595 DCHECK(UnlockVault(trans->GetWrappedTrans()).cryptographer.is_ready()); |
| 477 for (ModelTypeSet::Iterator iter = | 596 for (ModelTypeSet::Iterator iter = |
| 478 UnlockVault(trans->GetWrappedTrans()).encrypted_types.First(); | 597 UnlockVault(trans->GetWrappedTrans()).encrypted_types.First(); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 537 OnEncryptionComplete()); | 656 OnEncryptionComplete()); |
| 538 } | 657 } |
| 539 | 658 |
| 540 bool SyncEncryptionHandlerImpl::ApplyNigoriUpdateImpl( | 659 bool SyncEncryptionHandlerImpl::ApplyNigoriUpdateImpl( |
| 541 const sync_pb::NigoriSpecifics& nigori, | 660 const sync_pb::NigoriSpecifics& nigori, |
| 542 syncable::BaseTransaction* const trans) { | 661 syncable::BaseTransaction* const trans) { |
| 543 DCHECK(thread_checker_.CalledOnValidThread()); | 662 DCHECK(thread_checker_.CalledOnValidThread()); |
| 544 DVLOG(1) << "Applying nigori node update."; | 663 DVLOG(1) << "Applying nigori node update."; |
| 545 bool nigori_types_need_update = !UpdateEncryptedTypesFromNigori(nigori, | 664 bool nigori_types_need_update = !UpdateEncryptedTypesFromNigori(nigori, |
| 546 trans); | 665 trans); |
| 547 if (nigori.using_explicit_passphrase() && | 666 bool is_nigori_migrated = IsNigoriMigratedToKeystore(nigori); |
| 548 passphrase_state_ != CUSTOM_PASSPHRASE) { | 667 if (is_nigori_migrated) { |
| 549 passphrase_state_ = CUSTOM_PASSPHRASE; | 668 migration_time_ms_ = nigori.keystore_migration_time(); |
| 550 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, | 669 PassphraseState nigori_passphrase_state = |
| 551 OnPassphraseStateChanged(passphrase_state_)); | 670 ProtoPassphraseStateToEnum(nigori.passphrase_state()); |
| 671 | |
| 672 // Only update the local passphrase state if it's a valid transition: | |
| 673 // - implicit -> keystore | |
| 674 // - implicit -> frozen implicit | |
| 675 // - implicit -> custom | |
| 676 // - keystore -> custom | |
| 677 if (passphrase_state_ != nigori_passphrase_state && | |
| 678 nigori_passphrase_state != IMPLICIT_PASSPHRASE && | |
| 679 (passphrase_state_ == IMPLICIT_PASSPHRASE || | |
| 680 nigori_passphrase_state == CUSTOM_PASSPHRASE)) { | |
| 681 DVLOG(1) << "Changing passphrase state from " | |
| 682 << PassphraseStateToString(passphrase_state_) | |
| 683 << " to " | |
| 684 << PassphraseStateToString(nigori_passphrase_state); | |
| 685 passphrase_state_ = nigori_passphrase_state; | |
| 686 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, | |
| 687 OnPassphraseStateChanged(passphrase_state_)); | |
| 688 } | |
| 689 if (passphrase_state_ == KEYSTORE_PASSPHRASE && encrypt_everything_) { | |
| 690 DVLOG(1) << "Changing passphrase state to FROZEN_IMPLICIT_PASSPHRASE " | |
| 691 << "due to full encryption."; | |
| 692 passphrase_state_ = FROZEN_IMPLICIT_PASSPHRASE; | |
| 693 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, | |
| 694 OnPassphraseStateChanged(passphrase_state_)); | |
| 695 } | |
| 696 } else { | |
| 697 // It's possible that while we're waiting for migration another old | |
| 698 // client enables a custom passphrase. | |
| 699 if (nigori.frozen_keybag() && | |
| 700 passphrase_state_ != CUSTOM_PASSPHRASE) { | |
| 701 passphrase_state_ = CUSTOM_PASSPHRASE; | |
| 702 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, | |
| 703 OnPassphraseStateChanged(passphrase_state_)); | |
| 704 } | |
| 552 } | 705 } |
| 553 | 706 |
| 554 Cryptographer* cryptographer = &UnlockVaultMutable(trans)->cryptographer; | 707 Cryptographer* cryptographer = &UnlockVaultMutable(trans)->cryptographer; |
| 555 bool nigori_needs_new_keys = false; | 708 bool nigori_needs_new_keys = false; |
| 556 if (!nigori.encrypted().blob().empty()) { | 709 if (!nigori.encryption_keybag().blob().empty()) { |
| 557 if (cryptographer->CanDecrypt(nigori.encrypted())) { | 710 // We only update the default passphrase if this was a new explicit |
| 558 cryptographer->InstallKeys(nigori.encrypted()); | 711 // passphrase. Else, since it was decryptable, it must not have been a new |
| 559 // We only update the default passphrase if this was a new explicit | 712 // key. |
| 560 // passphrase. Else, since it was decryptable, it must not have been a new | 713 bool need_new_default = false; |
| 714 if (is_nigori_migrated) { | |
| 715 need_new_default = IsExplicitPassphrase( | |
| 716 ProtoPassphraseStateToEnum(nigori.passphrase_state())); | |
| 717 } else { | |
| 718 need_new_default = nigori.frozen_keybag(); | |
| 719 } | |
| 720 if (!AttemptToInstallKeybag(nigori.encryption_keybag(), | |
| 721 need_new_default, | |
| 722 cryptographer)) { | |
| 723 // Check to see if we can decrypt the keybag using the keystore bootstrap | |
| 561 // key. | 724 // key. |
| 562 if (nigori.using_explicit_passphrase()) | 725 cryptographer->SetPendingKeys(nigori.encryption_keybag()); |
| 563 cryptographer->SetDefaultKey(nigori.encrypted().key_name()); | 726 if (!nigori.keystore_bootstrap().blob().empty() && |
| 564 | 727 !keystore_key_.empty()) { |
| 565 // Check if the cryptographer's keybag is newer than the nigori's | 728 if (DecryptPendingKeysWithKeystoreKey(keystore_key_, |
| 566 // keybag. If so, we need to overwrite the nigori node. | 729 nigori.keystore_bootstrap(), |
| 567 sync_pb::EncryptedData new_keys = nigori.encrypted(); | 730 cryptographer)) { |
| 568 if (!cryptographer->GetKeys(&new_keys)) | 731 nigori_needs_new_keys = |
| 569 NOTREACHED(); | 732 cryptographer->KeybagIsStale(nigori.encryption_keybag()); |
| 570 if (nigori.encrypted().SerializeAsString() != | 733 } else { |
| 571 new_keys.SerializeAsString()) | 734 LOG(ERROR) << "Failed to decrypt pending keys using keystore " |
| 572 nigori_needs_new_keys = true; | 735 << "bootstrap key."; |
| 736 } | |
| 737 } | |
| 573 } else { | 738 } else { |
| 574 cryptographer->SetPendingKeys(nigori.encrypted()); | 739 // Keybag was installed. We write back our local keybag into the nigori |
| 740 // node if the nigori node's keybag either contains less keys or | |
| 741 // has a different default key. | |
| 742 nigori_needs_new_keys = | |
| 743 cryptographer->KeybagIsStale(nigori.encryption_keybag()); | |
| 575 } | 744 } |
| 576 } else { | 745 } else { |
| 746 // The nigori node has an empty encryption keybag. Attempt to write our | |
| 747 // local encryption keys into it. | |
| 748 LOG(WARNING) << "Nigori had empty encryption keybag."; | |
| 577 nigori_needs_new_keys = true; | 749 nigori_needs_new_keys = true; |
| 578 } | 750 } |
| 579 | 751 |
| 580 // If we've completed a sync cycle and the cryptographer isn't ready | 752 // If we've completed a sync cycle and the cryptographer isn't ready |
| 581 // yet or has pending keys, prompt the user for a passphrase. | 753 // yet or has pending keys, prompt the user for a passphrase. |
| 582 if (cryptographer->has_pending_keys()) { | 754 if (cryptographer->has_pending_keys()) { |
| 583 DVLOG(1) << "OnPassphraseRequired Sent"; | 755 DVLOG(1) << "OnPassphraseRequired Sent"; |
| 584 sync_pb::EncryptedData pending_keys = cryptographer->GetPendingKeys(); | 756 sync_pb::EncryptedData pending_keys = cryptographer->GetPendingKeys(); |
| 585 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, | 757 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, |
| 586 OnPassphraseRequired(REASON_DECRYPTION, | 758 OnPassphraseRequired(REASON_DECRYPTION, |
| 587 pending_keys)); | 759 pending_keys)); |
| 588 } else if (!cryptographer->is_ready()) { | 760 } else if (!cryptographer->is_ready()) { |
| 589 DVLOG(1) << "OnPassphraseRequired sent because cryptographer is not " | 761 DVLOG(1) << "OnPassphraseRequired sent because cryptographer is not " |
| 590 << "ready"; | 762 << "ready"; |
| 591 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, | 763 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, |
| 592 OnPassphraseRequired(REASON_ENCRYPTION, | 764 OnPassphraseRequired(REASON_ENCRYPTION, |
| 593 sync_pb::EncryptedData())); | 765 sync_pb::EncryptedData())); |
| 594 } | 766 } |
| 595 | 767 |
| 596 // Check if the current local encryption state is stricter/newer than the | 768 // Check if the current local encryption state is stricter/newer than the |
| 597 // nigori state. If so, we need to overwrite the nigori node with the local | 769 // nigori state. If so, we need to overwrite the nigori node with the local |
| 598 // state. | 770 // state. |
| 599 bool explicit_passphrase = passphrase_state_ == CUSTOM_PASSPHRASE; | 771 bool passphrase_state_matches = true; |
| 600 if (nigori.using_explicit_passphrase() != explicit_passphrase || | 772 if (!is_nigori_migrated) { |
| 773 DCHECK(passphrase_state_ == CUSTOM_PASSPHRASE || | |
| 774 passphrase_state_ == IMPLICIT_PASSPHRASE); | |
| 775 passphrase_state_matches = | |
| 776 nigori.frozen_keybag() == IsExplicitPassphrase(passphrase_state_); | |
| 777 } else { | |
| 778 passphrase_state_matches = | |
| 779 (ProtoPassphraseStateToEnum(nigori.passphrase_state()) == | |
| 780 passphrase_state_); | |
| 781 } | |
| 782 if (!passphrase_state_matches || | |
| 601 nigori.encrypt_everything() != encrypt_everything_ || | 783 nigori.encrypt_everything() != encrypt_everything_ || |
| 602 nigori_types_need_update || | 784 nigori_types_need_update || |
| 603 nigori_needs_new_keys) { | 785 nigori_needs_new_keys) { |
| 786 DVLOG(1) << "Triggering nigori rewrite."; | |
| 604 return false; | 787 return false; |
| 605 } | 788 } |
| 606 return true; | 789 return true; |
| 607 } | 790 } |
| 608 | 791 |
| 609 void SyncEncryptionHandlerImpl::RewriteNigori() { | 792 void SyncEncryptionHandlerImpl::RewriteNigori() { |
| 610 DVLOG(1) << "Overwriting stale nigori node."; | 793 DVLOG(1) << "Writing local encryption state into nigori."; |
| 611 DCHECK(thread_checker_.CalledOnValidThread()); | 794 DCHECK(thread_checker_.CalledOnValidThread()); |
| 612 WriteTransaction trans(FROM_HERE, user_share_); | 795 WriteTransaction trans(FROM_HERE, user_share_); |
| 613 WriteEncryptionStateToNigori(&trans); | 796 WriteEncryptionStateToNigori(&trans); |
| 614 } | 797 } |
| 615 | 798 |
| 616 void SyncEncryptionHandlerImpl::WriteEncryptionStateToNigori( | 799 void SyncEncryptionHandlerImpl::WriteEncryptionStateToNigori( |
| 617 WriteTransaction* trans) { | 800 WriteTransaction* trans) { |
| 618 DCHECK(thread_checker_.CalledOnValidThread()); | 801 DCHECK(thread_checker_.CalledOnValidThread()); |
| 619 WriteNode nigori_node(trans); | 802 WriteNode nigori_node(trans); |
| 620 // This can happen in tests that don't have nigori nodes. | 803 // This can happen in tests that don't have nigori nodes. |
| 621 if (nigori_node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK) | 804 if (nigori_node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK) |
| 622 return; | 805 return; |
| 806 | |
| 623 sync_pb::NigoriSpecifics nigori = nigori_node.GetNigoriSpecifics(); | 807 sync_pb::NigoriSpecifics nigori = nigori_node.GetNigoriSpecifics(); |
| 624 const Cryptographer& cryptographer = | 808 const Cryptographer& cryptographer = |
| 625 UnlockVault(trans->GetWrappedTrans()).cryptographer; | 809 UnlockVault(trans->GetWrappedTrans()).cryptographer; |
| 626 if (cryptographer.is_ready() && | |
| 627 nigori_overwrite_count_ < kNigoriOverwriteLimit) { | |
| 628 // Does not modify the encrypted blob if the unencrypted data already | |
| 629 // matches what is about to be written. | |
| 630 sync_pb::EncryptedData original_keys = nigori.encrypted(); | |
| 631 if (!cryptographer.GetKeys(nigori.mutable_encrypted())) | |
| 632 NOTREACHED(); | |
| 633 | 810 |
| 634 if (nigori.encrypted().SerializeAsString() != | 811 // Will not do anything if we shouldn't or can't migrate. Otherwise |
| 635 original_keys.SerializeAsString()) { | 812 // migrates, writing the full encryption state as it does. |
| 636 // We've updated the nigori node's encryption keys. In order to prevent | 813 if (!AttemptToMigrateNigoriToKeystore(trans, &nigori_node)) { |
| 637 // a possible looping of two clients constantly overwriting each other, | 814 if (cryptographer.is_ready() && |
| 638 // we limit the absolute number of overwrites per client instantiation. | 815 nigori_overwrite_count_ < kNigoriOverwriteLimit) { |
| 639 nigori_overwrite_count_++; | 816 // Does not modify the encrypted blob if the unencrypted data already |
| 640 UMA_HISTOGRAM_COUNTS("Sync.AutoNigoriOverwrites", | 817 // matches what is about to be written. |
| 641 nigori_overwrite_count_); | 818 sync_pb::EncryptedData original_keys = nigori.encryption_keybag(); |
| 819 if (!cryptographer.GetKeys(nigori.mutable_encryption_keybag())) | |
| 820 NOTREACHED(); | |
| 821 | |
| 822 if (nigori.encryption_keybag().SerializeAsString() != | |
| 823 original_keys.SerializeAsString()) { | |
| 824 // We've updated the nigori node's encryption keys. In order to prevent | |
| 825 // a possible looping of two clients constantly overwriting each other, | |
| 826 // we limit the absolute number of overwrites per client instantiation. | |
| 827 nigori_overwrite_count_++; | |
| 828 UMA_HISTOGRAM_COUNTS("Sync.AutoNigoriOverwrites", | |
| 829 nigori_overwrite_count_); | |
| 830 } | |
| 831 | |
| 832 // Note: we don't try to set frozen_keybag here since if that | |
| 833 // is lost the user can always set it again (and we don't want to clobber | |
| 834 // any migration state). The main goal at this point is to preserve | |
| 835 // the encryption keys so all data remains decryptable. | |
| 642 } | 836 } |
| 837 syncable::UpdateNigoriFromEncryptedTypes( | |
| 838 UnlockVault(trans->GetWrappedTrans()).encrypted_types, | |
| 839 encrypt_everything_, | |
| 840 &nigori); | |
| 643 | 841 |
| 644 // Note: we don't try to set using_explicit_passphrase here since if that | 842 // If nothing has changed, this is a no-op. |
| 645 // is lost the user can always set it again. The main point is to preserve | 843 nigori_node.SetNigoriSpecifics(nigori); |
| 646 // the encryption keys so all data remains decryptable. | |
| 647 } | 844 } |
| 648 syncable::UpdateNigoriFromEncryptedTypes( | |
| 649 UnlockVault(trans->GetWrappedTrans()).encrypted_types, | |
| 650 encrypt_everything_, | |
| 651 &nigori); | |
| 652 | |
| 653 // If nothing has changed, this is a no-op. | |
| 654 nigori_node.SetNigoriSpecifics(nigori); | |
| 655 } | 845 } |
| 656 | 846 |
| 657 bool SyncEncryptionHandlerImpl::UpdateEncryptedTypesFromNigori( | 847 bool SyncEncryptionHandlerImpl::UpdateEncryptedTypesFromNigori( |
| 658 const sync_pb::NigoriSpecifics& nigori, | 848 const sync_pb::NigoriSpecifics& nigori, |
| 659 syncable::BaseTransaction* const trans) { | 849 syncable::BaseTransaction* const trans) { |
| 660 DCHECK(thread_checker_.CalledOnValidThread()); | 850 DCHECK(thread_checker_.CalledOnValidThread()); |
| 661 ModelTypeSet* encrypted_types = &UnlockVaultMutable(trans)->encrypted_types; | 851 ModelTypeSet* encrypted_types = &UnlockVaultMutable(trans)->encrypted_types; |
| 662 if (nigori.encrypt_everything()) { | 852 if (nigori.encrypt_everything()) { |
| 663 if (!encrypt_everything_) { | 853 EnableEncryptEverythingImpl(trans); |
| 664 encrypt_everything_ = true; | |
| 665 *encrypted_types = ModelTypeSet::All(); | |
| 666 DVLOG(1) << "Enabling encrypt everything via nigori node update"; | |
| 667 FOR_EACH_OBSERVER( | |
| 668 Observer, observers_, | |
| 669 OnEncryptedTypesChanged(*encrypted_types, encrypt_everything_)); | |
| 670 } | |
| 671 DCHECK(encrypted_types->Equals(ModelTypeSet::All())); | 854 DCHECK(encrypted_types->Equals(ModelTypeSet::All())); |
| 672 return true; | 855 return true; |
| 856 } else if (encrypt_everything_) { | |
| 857 DCHECK(encrypted_types->Equals(ModelTypeSet::All())); | |
| 858 return false; | |
| 673 } | 859 } |
| 674 | 860 |
| 675 ModelTypeSet nigori_encrypted_types; | 861 ModelTypeSet nigori_encrypted_types; |
| 676 nigori_encrypted_types = syncable::GetEncryptedTypesFromNigori(nigori); | 862 nigori_encrypted_types = syncable::GetEncryptedTypesFromNigori(nigori); |
| 677 nigori_encrypted_types.PutAll(SensitiveTypes()); | 863 nigori_encrypted_types.PutAll(SensitiveTypes()); |
| 678 | 864 |
| 679 // If anything more than the sensitive types were encrypted, and | 865 // If anything more than the sensitive types were encrypted, and |
| 680 // encrypt_everything is not explicitly set to false, we assume it means | 866 // encrypt_everything is not explicitly set to false, we assume it means |
| 681 // a client intended to enable encrypt everything. | 867 // a client intended to enable encrypt everything. |
| 682 if (!nigori.has_encrypt_everything() && | 868 if (!nigori.has_encrypt_everything() && |
| 683 !Difference(nigori_encrypted_types, SensitiveTypes()).Empty()) { | 869 !Difference(nigori_encrypted_types, SensitiveTypes()).Empty()) { |
| 684 if (!encrypt_everything_) { | 870 if (!encrypt_everything_) { |
| 685 encrypt_everything_ = true; | 871 encrypt_everything_ = true; |
| 686 *encrypted_types = ModelTypeSet::All(); | 872 *encrypted_types = ModelTypeSet::All(); |
| 687 FOR_EACH_OBSERVER( | 873 FOR_EACH_OBSERVER( |
| 688 Observer, observers_, | 874 Observer, observers_, |
| 689 OnEncryptedTypesChanged(*encrypted_types, encrypt_everything_)); | 875 OnEncryptedTypesChanged(*encrypted_types, encrypt_everything_)); |
| 690 } | 876 } |
| 691 DCHECK(encrypted_types->Equals(ModelTypeSet::All())); | 877 DCHECK(encrypted_types->Equals(ModelTypeSet::All())); |
| 692 return false; | 878 return false; |
| 693 } | 879 } |
| 694 | 880 |
| 695 MergeEncryptedTypes(nigori_encrypted_types, trans); | 881 MergeEncryptedTypes(nigori_encrypted_types, trans); |
| 696 return encrypted_types->Equals(nigori_encrypted_types); | 882 return encrypted_types->Equals(nigori_encrypted_types); |
| 697 } | 883 } |
| 698 | 884 |
| 885 void SyncEncryptionHandlerImpl::SetCustomPassphrase( | |
| 886 const std::string& passphrase, | |
| 887 WriteTransaction* trans, | |
| 888 WriteNode* nigori_node) { | |
| 889 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 890 KeyParams key_params = {"localhost", "dummy", passphrase}; | |
| 891 | |
| 892 if (passphrase_state_ != KEYSTORE_PASSPHRASE) { | |
| 893 DVLOG(1) << "Failing to set a custom passphrase because one has already " | |
| 894 << "been set."; | |
| 895 FinishSetPassphrase(false, "", trans, nigori_node); | |
| 896 return; | |
| 897 } | |
| 898 | |
| 899 Cryptographer* cryptographer = | |
| 900 &UnlockVaultMutable(trans->GetWrappedTrans())->cryptographer; | |
| 901 if (cryptographer->has_pending_keys()) { | |
| 902 // This theoretically shouldn't happen, because the only way to have pending | |
| 903 // keys after migrating to keystore support is if a custom passphrase was | |
|
tim (not reviewing)
2012/09/06 01:04:20
Is there an assertion we can make (DCHECK) that we
Nicolas Zea
2012/09/06 21:45:27
Done.
| |
| 904 // set, which should update passpshrase_state_ and should be caught by the | |
| 905 // if statement above. For the sake of safety though, we check for it in | |
| 906 // case a client is misbehaving. | |
| 907 LOG(ERROR) << "Failing to set custom passphrase because of pending keys."; | |
| 908 FinishSetPassphrase(false, "", trans, nigori_node); | |
| 909 return; | |
| 910 } | |
| 911 | |
| 912 std::string bootstrap_token; | |
| 913 if (cryptographer->AddKey(key_params)) { | |
| 914 DVLOG(1) << "Setting custom passphrase."; | |
| 915 cryptographer->GetBootstrapToken(&bootstrap_token); | |
| 916 passphrase_state_ = CUSTOM_PASSPHRASE; | |
| 917 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, | |
| 918 OnPassphraseStateChanged(passphrase_state_)); | |
| 919 } else { | |
| 920 NOTREACHED() << "Failed to add key to cryptographer."; | |
| 921 return; | |
| 922 } | |
| 923 FinishSetPassphrase(true, bootstrap_token, trans, nigori_node); | |
| 924 } | |
| 925 | |
| 926 void SyncEncryptionHandlerImpl::DecryptExplicitPassphrase( | |
| 927 const std::string& passphrase, | |
| 928 WriteTransaction* trans, | |
| 929 WriteNode* nigori_node) { | |
| 930 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 931 DCHECK(IsExplicitPassphrase(passphrase_state_)); | |
| 932 KeyParams key_params = {"localhost", "dummy", passphrase}; | |
| 933 | |
| 934 Cryptographer* cryptographer = | |
| 935 &UnlockVaultMutable(trans->GetWrappedTrans())->cryptographer; | |
| 936 if (!cryptographer->has_pending_keys()) { | |
| 937 // Note that this *can* happen in a rare situation where data is | |
| 938 // re-encrypted on another client while a SetDecryptionPassphrase() call is | |
| 939 // in-flight on this client. It is rare enough that we choose to do nothing. | |
| 940 NOTREACHED() << "Attempt to set decryption passphrase failed because there " | |
| 941 << "were no pending keys."; | |
| 942 return; | |
| 943 } | |
| 944 | |
| 945 DCHECK(IsExplicitPassphrase(passphrase_state_)); | |
| 946 bool success = false; | |
| 947 std::string bootstrap_token; | |
| 948 if (cryptographer->DecryptPendingKeys(key_params)) { | |
| 949 DVLOG(1) << "Explicit passphrase accepted for decryption."; | |
| 950 cryptographer->GetBootstrapToken(&bootstrap_token); | |
| 951 success = true; | |
| 952 } else { | |
| 953 DVLOG(1) << "Explicit passphrase failed to decrypt."; | |
| 954 success = false; | |
| 955 } | |
| 956 if (success && !keystore_key_.empty()) { | |
| 957 // Should already be part of the encryption keybag, but we add it just | |
| 958 // in case. | |
| 959 KeyParams key_params = {"localhost", "dummy", keystore_key_}; | |
| 960 cryptographer->AddNonDefaultKey(key_params); | |
| 961 } | |
| 962 FinishSetPassphrase(success, bootstrap_token, trans, nigori_node); | |
| 963 } | |
| 964 | |
| 699 void SyncEncryptionHandlerImpl::FinishSetPassphrase( | 965 void SyncEncryptionHandlerImpl::FinishSetPassphrase( |
| 700 bool success, | 966 bool success, |
| 701 const std::string& bootstrap_token, | 967 const std::string& bootstrap_token, |
|
tim (not reviewing)
2012/09/06 01:04:20
Why do we pass this in if we're poking around at t
Nicolas Zea
2012/09/06 21:45:27
Due to the old SetEncryptionPassphrase logic, we n
| |
| 702 bool is_explicit, | |
| 703 WriteTransaction* trans, | 968 WriteTransaction* trans, |
| 704 WriteNode* nigori_node) { | 969 WriteNode* nigori_node) { |
| 705 DCHECK(thread_checker_.CalledOnValidThread()); | 970 DCHECK(thread_checker_.CalledOnValidThread()); |
| 706 FOR_EACH_OBSERVER( | 971 FOR_EACH_OBSERVER( |
| 707 SyncEncryptionHandler::Observer, | 972 SyncEncryptionHandler::Observer, |
| 708 observers_, | 973 observers_, |
| 709 OnCryptographerStateChanged( | 974 OnCryptographerStateChanged( |
| 710 &UnlockVaultMutable(trans->GetWrappedTrans())->cryptographer)); | 975 &UnlockVaultMutable(trans->GetWrappedTrans())->cryptographer)); |
| 711 | 976 |
| 712 // It's possible we need to change the bootstrap token even if we failed to | 977 // It's possible we need to change the bootstrap token even if we failed to |
| 713 // set the passphrase (for example if we need to preserve the new GAIA | 978 // set the passphrase (for example if we need to preserve the new GAIA |
| 714 // passphrase). | 979 // passphrase). |
|
tim (not reviewing)
2012/09/06 01:04:20
I guess this is still relevant...
Nicolas Zea
2012/09/06 21:45:27
Right, see my response above.
| |
| 715 if (!bootstrap_token.empty()) { | 980 if (!bootstrap_token.empty()) { |
| 716 DVLOG(1) << "Passphrase bootstrap token updated."; | 981 DVLOG(1) << "Passphrase bootstrap token updated."; |
| 717 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, | 982 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, |
| 718 OnBootstrapTokenUpdated(bootstrap_token, | 983 OnBootstrapTokenUpdated(bootstrap_token, |
| 719 PASSPHRASE_BOOTSTRAP_TOKEN)); | 984 PASSPHRASE_BOOTSTRAP_TOKEN)); |
| 720 } | 985 } |
| 721 | 986 |
| 722 const Cryptographer& cryptographer = | 987 const Cryptographer& cryptographer = |
| 723 UnlockVault(trans->GetWrappedTrans()).cryptographer; | 988 UnlockVault(trans->GetWrappedTrans()).cryptographer; |
| 724 if (!success) { | 989 if (!success) { |
| 725 if (cryptographer.is_ready()) { | 990 if (cryptographer.is_ready()) { |
| 726 LOG(ERROR) << "Attempt to change passphrase failed while cryptographer " | 991 LOG(ERROR) << "Attempt to change passphrase failed while cryptographer " |
| 727 << "was ready."; | 992 << "was ready."; |
| 728 } else if (cryptographer.has_pending_keys()) { | 993 } else if (cryptographer.has_pending_keys()) { |
| 729 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, | 994 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, |
| 730 OnPassphraseRequired(REASON_DECRYPTION, | 995 OnPassphraseRequired(REASON_DECRYPTION, |
| 731 cryptographer.GetPendingKeys())); | 996 cryptographer.GetPendingKeys())); |
| 732 } else { | 997 } else { |
| 733 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, | 998 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, |
| 734 OnPassphraseRequired(REASON_ENCRYPTION, | 999 OnPassphraseRequired(REASON_ENCRYPTION, |
| 735 sync_pb::EncryptedData())); | 1000 sync_pb::EncryptedData())); |
| 736 } | 1001 } |
| 737 return; | 1002 return; |
| 738 } | 1003 } |
| 739 | 1004 DCHECK(success); |
| 740 DCHECK(cryptographer.is_ready()); | 1005 DCHECK(cryptographer.is_ready()); |
| 741 | 1006 |
| 742 // TODO(zea): trigger migration if necessary. | 1007 // Will do nothing if we're already properly migrated or unable to migrate. |
| 743 | 1008 // Otherwise will update the nigori node with the current migrated state, |
| 744 sync_pb::NigoriSpecifics specifics(nigori_node->GetNigoriSpecifics()); | 1009 // writing all encryption state as it does. |
| 745 // Does not modify specifics.encrypted() if the original decrypted data was | 1010 if (!AttemptToMigrateNigoriToKeystore(trans, nigori_node)) { |
| 746 // the same. | 1011 sync_pb::NigoriSpecifics nigori(nigori_node->GetNigoriSpecifics()); |
| 747 if (!cryptographer.GetKeys(specifics.mutable_encrypted())) | 1012 // Does not modify nigori.encryption_keybag() if the original decrypted |
| 748 NOTREACHED(); | 1013 // data was the same. |
| 749 if (is_explicit && passphrase_state_ != CUSTOM_PASSPHRASE) { | 1014 if (!cryptographer.GetKeys(nigori.mutable_encryption_keybag())) |
| 750 passphrase_state_ = CUSTOM_PASSPHRASE; | 1015 NOTREACHED(); |
| 751 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, | 1016 if (IsNigoriMigratedToKeystore(nigori)) { |
| 752 OnPassphraseStateChanged(passphrase_state_)); | 1017 DCHECK(keystore_key_.empty() || IsExplicitPassphrase(passphrase_state_)); |
| 1018 DVLOG(1) << "Leaving nigori migration state untouched after setting" | |
| 1019 << " passphrase."; | |
| 1020 } else { | |
| 1021 nigori.set_frozen_keybag( | |
| 1022 IsExplicitPassphrase(passphrase_state_)); | |
| 1023 } | |
| 1024 nigori_node->SetNigoriSpecifics(nigori); | |
| 753 } | 1025 } |
| 754 specifics.set_using_explicit_passphrase(is_explicit); | |
| 755 nigori_node->SetNigoriSpecifics(specifics); | |
| 756 | 1026 |
| 757 // Must do this after OnPassphraseStateChanged, in order to ensure the PSS | 1027 // Must do this after OnPassphraseStateChanged, in order to ensure the PSS |
| 758 // checks the passphrase state after it has been set. | 1028 // checks the passphrase state after it has been set. |
| 759 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, | 1029 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, |
| 760 OnPassphraseAccepted()); | 1030 OnPassphraseAccepted()); |
| 761 | 1031 |
| 762 // Does nothing if everything is already encrypted. | 1032 // Does nothing if everything is already encrypted. |
| 1033 // TODO(zea): If we just migrated and enabled encryption, this will be | |
| 1034 // redundant. Figure out a way to not do this unnecessarily. | |
| 763 ReEncryptEverything(trans); | 1035 ReEncryptEverything(trans); |
| 764 } | 1036 } |
| 765 | 1037 |
| 766 void SyncEncryptionHandlerImpl::MergeEncryptedTypes( | 1038 void SyncEncryptionHandlerImpl::MergeEncryptedTypes( |
| 767 ModelTypeSet new_encrypted_types, | 1039 ModelTypeSet new_encrypted_types, |
| 768 syncable::BaseTransaction* const trans) { | 1040 syncable::BaseTransaction* const trans) { |
| 769 DCHECK(thread_checker_.CalledOnValidThread()); | 1041 DCHECK(thread_checker_.CalledOnValidThread()); |
| 770 ModelTypeSet* encrypted_types = &UnlockVaultMutable(trans)->encrypted_types; | 1042 ModelTypeSet* encrypted_types = &UnlockVaultMutable(trans)->encrypted_types; |
| 771 if (!encrypted_types->HasAll(new_encrypted_types)) { | 1043 if (!encrypted_types->HasAll(new_encrypted_types)) { |
| 772 *encrypted_types = new_encrypted_types; | 1044 *encrypted_types = new_encrypted_types; |
| 773 FOR_EACH_OBSERVER( | 1045 FOR_EACH_OBSERVER( |
| 774 Observer, observers_, | 1046 Observer, observers_, |
| 775 OnEncryptedTypesChanged(*encrypted_types, encrypt_everything_)); | 1047 OnEncryptedTypesChanged(*encrypted_types, encrypt_everything_)); |
| 776 } | 1048 } |
| 777 } | 1049 } |
| 778 | 1050 |
| 779 SyncEncryptionHandlerImpl::Vault* SyncEncryptionHandlerImpl::UnlockVaultMutable( | 1051 SyncEncryptionHandlerImpl::Vault* SyncEncryptionHandlerImpl::UnlockVaultMutable( |
| 780 syncable::BaseTransaction* const trans) { | 1052 syncable::BaseTransaction* const trans) { |
| 781 DCHECK_EQ(user_share_->directory.get(), trans->directory()); | 1053 DCHECK_EQ(user_share_->directory.get(), trans->directory()); |
| 782 return &vault_unsafe_; | 1054 return &vault_unsafe_; |
| 783 } | 1055 } |
| 784 | 1056 |
| 785 const SyncEncryptionHandlerImpl::Vault& SyncEncryptionHandlerImpl::UnlockVault( | 1057 const SyncEncryptionHandlerImpl::Vault& SyncEncryptionHandlerImpl::UnlockVault( |
| 786 syncable::BaseTransaction* const trans) const { | 1058 syncable::BaseTransaction* const trans) const { |
| 787 DCHECK_EQ(user_share_->directory.get(), trans->directory()); | 1059 DCHECK_EQ(user_share_->directory.get(), trans->directory()); |
| 788 return vault_unsafe_; | 1060 return vault_unsafe_; |
| 789 } | 1061 } |
| 790 | 1062 |
| 1063 bool SyncEncryptionHandlerImpl::ShouldTriggerMigration( | |
| 1064 const sync_pb::NigoriSpecifics& nigori, | |
| 1065 const Cryptographer& cryptographer) const { | |
| 1066 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 1067 // TODO(zea): once we're willing to have the keystore key be the only | |
| 1068 // encryption key, change this to !has_pending_keys(). For now, we need the | |
| 1069 // cryptographer to be initialized with the current GAIA pass so that older | |
| 1070 // clients (that don't have keystore support) can decrypt the keybag. | |
| 1071 if (!cryptographer.is_ready()) | |
| 1072 return false; | |
| 1073 if (IsNigoriMigratedToKeystore(nigori)) { | |
| 1074 // If the nigori is already migrated but has an old passphrase state, | |
| 1075 // re-migrate. Similarly, if the nigori has an explicit passphrase but | |
| 1076 // does not have full encryption, or the nigori has an implicit passphrase | |
| 1077 // but does have full encryption, re-migrate. | |
| 1078 if (passphrase_state_ != KEYSTORE_PASSPHRASE && | |
| 1079 nigori.passphrase_state() == | |
| 1080 sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE) { | |
| 1081 return true; | |
| 1082 } else if (IsExplicitPassphrase(passphrase_state_) && | |
| 1083 !encrypt_everything_) { | |
| 1084 return true; | |
| 1085 } else if (passphrase_state_ == KEYSTORE_PASSPHRASE && | |
| 1086 encrypt_everything_) { | |
| 1087 return true; | |
| 1088 } else { | |
| 1089 return false; | |
| 1090 } | |
| 1091 } else if (keystore_key_.empty()) { | |
| 1092 // If we haven't already migrated, we don't want to do anything unless | |
| 1093 // a keystore key is available (so that those clients without keystore | |
| 1094 // encryption enabled aren't forced into new states, e.g. frozen implicit | |
| 1095 // passphrase). | |
| 1096 return false; | |
| 1097 } | |
| 1098 return true; | |
| 1099 } | |
| 1100 | |
| 1101 bool SyncEncryptionHandlerImpl::AttemptToMigrateNigoriToKeystore( | |
| 1102 WriteTransaction* trans, | |
| 1103 WriteNode* nigori_node) { | |
| 1104 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 1105 const sync_pb::NigoriSpecifics& old_nigori = | |
| 1106 nigori_node->GetNigoriSpecifics(); | |
| 1107 Cryptographer* cryptographer = | |
| 1108 &UnlockVaultMutable(trans->GetWrappedTrans())->cryptographer; | |
| 1109 | |
| 1110 if (!ShouldTriggerMigration(old_nigori, *cryptographer)) | |
| 1111 return false; | |
| 1112 | |
| 1113 DVLOG(1) << "Starting nigori migration to keystore support."; | |
| 1114 if (migration_time_ms_ == 0) | |
| 1115 migration_time_ms_ = TimeToProtoTime(base::Time::Now()); | |
| 1116 sync_pb::NigoriSpecifics migrated_nigori(old_nigori); | |
| 1117 migrated_nigori.set_keystore_migration_time(migration_time_ms_); | |
| 1118 | |
| 1119 PassphraseState new_passphrase_state = passphrase_state_; | |
| 1120 bool new_encrypt_everything = encrypt_everything_; | |
| 1121 if (encrypt_everything_ && !IsExplicitPassphrase(passphrase_state_)) { | |
| 1122 DVLOG(1) << "Switching to frozen implicit passphrase due to already having " | |
| 1123 << "full encryption."; | |
| 1124 new_passphrase_state = FROZEN_IMPLICIT_PASSPHRASE; | |
| 1125 migrated_nigori.clear_keystore_bootstrap(); | |
| 1126 } else if (IsExplicitPassphrase(passphrase_state_)) { | |
| 1127 DVLOG_IF(1, !encrypt_everything_) << "Enabling encrypt everything due to " | |
| 1128 << "explicit passphrase"; | |
| 1129 new_encrypt_everything = true; | |
| 1130 migrated_nigori.clear_keystore_bootstrap(); | |
| 1131 } else { | |
| 1132 DCHECK_EQ(passphrase_state_, IMPLICIT_PASSPHRASE); | |
| 1133 DCHECK(!encrypt_everything_); | |
| 1134 new_passphrase_state = KEYSTORE_PASSPHRASE; | |
| 1135 DVLOG(1) << "Switching to keystore passphrase state."; | |
| 1136 } | |
| 1137 migrated_nigori.set_encrypt_everything(new_encrypt_everything); | |
| 1138 migrated_nigori.set_passphrase_state( | |
| 1139 EnumPassphraseStateToProto(new_passphrase_state)); | |
| 1140 migrated_nigori.set_frozen_keybag(true); | |
| 1141 | |
| 1142 if (!keystore_key_.empty()) { | |
| 1143 KeyParams key_params = {"localhost", "dummy", keystore_key_}; | |
| 1144 if (!cryptographer->AddNonDefaultKey(key_params)) { | |
| 1145 LOG(ERROR) << "Failed to add keystore key as non-default key."; | |
| 1146 return false; | |
| 1147 } | |
| 1148 } | |
| 1149 if (new_passphrase_state == KEYSTORE_PASSPHRASE && | |
| 1150 !GetKeystoreBootstrapKey( | |
| 1151 *cryptographer, | |
| 1152 keystore_key_, | |
| 1153 migrated_nigori.mutable_keystore_bootstrap())) { | |
| 1154 LOG(ERROR) << "Failed to extract keystore bootstrap key."; | |
| 1155 return false; | |
| 1156 } | |
| 1157 if (!cryptographer->GetKeys(migrated_nigori.mutable_encryption_keybag())) { | |
| 1158 LOG(ERROR) << "Failed to extract encryption keybag."; | |
| 1159 return false; | |
| 1160 } | |
| 1161 | |
| 1162 DVLOG(1) << "Completing nigori migration to keystore support."; | |
| 1163 nigori_node->SetNigoriSpecifics(migrated_nigori); | |
| 1164 if (passphrase_state_ != new_passphrase_state) { | |
| 1165 passphrase_state_ = new_passphrase_state; | |
| 1166 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, | |
| 1167 OnPassphraseStateChanged(passphrase_state_)); | |
| 1168 } | |
| 1169 if (new_encrypt_everything && !encrypt_everything_) { | |
| 1170 EnableEncryptEverythingImpl(trans->GetWrappedTrans()); | |
| 1171 ReEncryptEverything(trans); | |
| 1172 } | |
| 1173 return true; | |
| 1174 } | |
| 1175 | |
| 1176 bool SyncEncryptionHandlerImpl::GetKeystoreBootstrapKey( | |
| 1177 const Cryptographer& cryptographer, | |
| 1178 const std::string& keystore_key, | |
| 1179 sync_pb::EncryptedData* encrypted_blob) { | |
| 1180 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 1181 DCHECK(!keystore_key.empty()); | |
| 1182 DCHECK(cryptographer.is_ready()); | |
| 1183 std::string bootstrap_token; | |
| 1184 if (!cryptographer.GetBootstrapToken(&bootstrap_token)) { | |
| 1185 LOG(ERROR) << "Failed to get cryptographer bootstrap token."; | |
| 1186 return false; | |
| 1187 } | |
| 1188 Cryptographer temp_cryptographer(cryptographer.encryptor()); | |
| 1189 KeyParams key_params = {"localhost", "dummy", keystore_key}; | |
| 1190 if (!temp_cryptographer.AddKey(key_params)) | |
| 1191 return false; | |
| 1192 if (!temp_cryptographer.EncryptString(bootstrap_token, encrypted_blob)) | |
| 1193 return false; | |
| 1194 return true; | |
| 1195 } | |
| 1196 | |
| 1197 bool SyncEncryptionHandlerImpl::AttemptToInstallKeybag( | |
| 1198 const sync_pb::EncryptedData& keybag, | |
| 1199 bool update_default, | |
| 1200 Cryptographer* cryptographer) { | |
| 1201 if (!cryptographer->CanDecrypt(keybag)) | |
| 1202 return false; | |
| 1203 cryptographer->InstallKeys(keybag); | |
| 1204 if (update_default) | |
| 1205 cryptographer->SetDefaultKey(keybag.key_name()); | |
| 1206 return true; | |
| 1207 } | |
| 1208 | |
| 1209 void SyncEncryptionHandlerImpl::EnableEncryptEverythingImpl( | |
| 1210 syncable::BaseTransaction* const trans) { | |
| 1211 ModelTypeSet* encrypted_types = &UnlockVaultMutable(trans)->encrypted_types; | |
| 1212 if (encrypt_everything_) { | |
| 1213 DCHECK(encrypted_types->Equals(ModelTypeSet::All())); | |
| 1214 return; | |
| 1215 } | |
| 1216 encrypt_everything_ = true; | |
| 1217 *encrypted_types = ModelTypeSet::All(); | |
| 1218 FOR_EACH_OBSERVER( | |
| 1219 Observer, observers_, | |
| 1220 OnEncryptedTypesChanged(*encrypted_types, encrypt_everything_)); | |
| 1221 } | |
| 1222 | |
| 1223 bool SyncEncryptionHandlerImpl::DecryptPendingKeysWithKeystoreKey( | |
| 1224 const std::string& keystore_key, | |
| 1225 const sync_pb::EncryptedData& keystore_bootstrap, | |
| 1226 Cryptographer* cryptographer) { | |
| 1227 DCHECK(cryptographer->has_pending_keys()); | |
| 1228 if (keystore_bootstrap.blob().empty()) | |
| 1229 return false; | |
|
tim (not reviewing)
2012/09/06 01:04:20
We don't need to notify if this fails because ther
Nicolas Zea
2012/09/06 21:45:27
If this fails, we'll remain in a pending keys stat
tim (not reviewing)
2012/09/10 20:41:52
How is the explicit passphrase UI triggered, then?
| |
| 1230 Cryptographer temp_cryptographer(cryptographer->encryptor()); | |
| 1231 KeyParams keystore_params = {"localhost", "dummy", keystore_key_}; | |
| 1232 if (temp_cryptographer.AddKey(keystore_params) && | |
| 1233 temp_cryptographer.CanDecrypt(keystore_bootstrap)) { | |
|
tim (not reviewing)
2012/09/06 01:04:20
"bootstrap tokens" as defined by Cryptographer are
Nicolas Zea
2012/09/06 21:45:27
Done.
| |
| 1234 // Someone else migrated the nigori for us! How generous! Go ahead and | |
| 1235 // install both the keystore key and the new default encryption key | |
| 1236 // (i.e. the one provided by the bootstrap key) into the | |
| 1237 // cryptographer. | |
| 1238 // The keystore bootstrap is a keystore encrypted bootstrap token containing | |
| 1239 // the current default encryption key (and as such should be able to | |
| 1240 // decrypt the encryption keybag). | |
| 1241 DVLOG(1) << "Attempting to decrypt pending keys using " | |
| 1242 << "keystore bootstrap."; | |
| 1243 std::string temp_bootstrap = | |
| 1244 temp_cryptographer.DecryptToString(keystore_bootstrap); | |
| 1245 // This will decrypt the pending keys and add them if possible. | |
| 1246 // The encryption key within temp_bootstrap will be the default after. | |
| 1247 cryptographer->AddKeyFromBootstrapToken(temp_bootstrap); | |
| 1248 // Theoretically the encryption keybag should already contain the keystore | |
| 1249 // key. We explicitly add it as a safety measure. | |
| 1250 cryptographer->AddNonDefaultKey(keystore_params); | |
| 1251 if (cryptographer->is_ready()) { | |
| 1252 DVLOG(1) << "Keystore bootstrap decrypted pending keys."; | |
| 1253 FOR_EACH_OBSERVER( | |
| 1254 SyncEncryptionHandler::Observer, | |
| 1255 observers_, | |
| 1256 OnBootstrapTokenUpdated(temp_bootstrap, | |
| 1257 PASSPHRASE_BOOTSTRAP_TOKEN)); | |
| 1258 FOR_EACH_OBSERVER( | |
| 1259 SyncEncryptionHandler::Observer, | |
| 1260 observers_, | |
| 1261 OnCryptographerStateChanged(cryptographer)); | |
| 1262 return true; | |
| 1263 } | |
| 1264 } | |
| 1265 return false; | |
| 1266 } | |
| 1267 | |
| 791 } // namespace browser_sync | 1268 } // namespace browser_sync |
| OLD | NEW |