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_decryptor_key is set. | |
| 50 bool IsNigoriMigratedToKeystore(const sync_pb::NigoriSpecifics& nigori) { | |
| 51 if (!nigori.has_passphrase_type()) | |
| 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_type() == | |
| 58 sync_pb::NigoriSpecifics::IMPLICIT_PASSPHRASE) | |
| 59 return false; | |
| 60 if (nigori.passphrase_type() == | |
| 61 sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE && | |
| 62 nigori.keystore_decryptor().blob().empty()) | |
| 63 return false; | |
| 64 return true; | |
| 38 } | 65 } |
| 39 | 66 |
| 67 PassphraseType ProtoPassphraseTypeToEnum( | |
| 68 sync_pb::NigoriSpecifics::PassphraseType type) { | |
| 69 switch(type) { | |
| 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::PassphraseType | |
| 85 EnumPassphraseTypeToProto(PassphraseType type) { | |
| 86 switch(type) { | |
| 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(PassphraseType type) { | |
| 102 return type == CUSTOM_PASSPHRASE || type == 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_type_(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 don't need to create an initial | |
| 212 // encryption key. | |
| 213 LOG(WARNING) << "Ignoring new implicit passphrase. Keystore migration " | |
| 214 << "already performed."; | |
| 215 return; | |
| 216 } | |
| 217 // Will fail if we already have an explicit passphrase or we have pending | |
| 218 // keys. | |
| 219 SetCustomPassphrase(passphrase, &trans, &node); | |
| 220 return; | |
| 221 } | |
| 222 | |
| 135 std::string bootstrap_token; | 223 std::string bootstrap_token; |
| 136 sync_pb::EncryptedData pending_keys; | 224 sync_pb::EncryptedData pending_keys; |
| 137 Cryptographer* cryptographer = | |
| 138 &UnlockVaultMutable(trans.GetWrappedTrans())->cryptographer; | |
| 139 if (cryptographer->has_pending_keys()) | 225 if (cryptographer->has_pending_keys()) |
| 140 pending_keys = cryptographer->GetPendingKeys(); | 226 pending_keys = cryptographer->GetPendingKeys(); |
| 141 bool success = false; | 227 bool success = false; |
| 142 | 228 |
| 143 // There are six cases to handle here: | 229 // There are six cases to handle here: |
| 144 // 1. The user has no pending keys and is setting their current GAIA password | 230 // 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 | 231 // 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 | 232 // with a clean profile, or after re-authenticating on a profile that was |
| 147 // already signed in with the cryptographer ready. | 233 // already signed in with the cryptographer ready. |
| 148 // 2. The user has no pending keys, and is overwriting an (already provided) | 234 // 2. The user has no pending keys, and is overwriting an (already provided) |
| 149 // implicit passphrase with an explicit (custom) passphrase. | 235 // implicit passphrase with an explicit (custom) passphrase. |
| 150 // 3. The user has pending keys for an explicit passphrase that is somehow set | 236 // 3. The user has pending keys for an explicit passphrase that is somehow set |
| 151 // to their current GAIA passphrase. | 237 // to their current GAIA passphrase. |
| 152 // 4. The user has pending keys encrypted with their current GAIA passphrase | 238 // 4. The user has pending keys encrypted with their current GAIA passphrase |
| 153 // and the caller passes in the current GAIA passphrase. | 239 // and the caller passes in the current GAIA passphrase. |
| 154 // 5. The user has pending keys encrypted with an older GAIA passphrase | 240 // 5. The user has pending keys encrypted with an older GAIA passphrase |
| 155 // and the caller passes in the current GAIA passphrase. | 241 // and the caller passes in the current GAIA passphrase. |
| 156 // 6. The user has previously done encryption with an explicit passphrase. | 242 // 6. The user has previously done encryption with an explicit passphrase. |
| 157 // Furthermore, we enforce the fact that the bootstrap encryption token will | 243 // 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 | 244 // 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 | 245 // 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 | 246 // password). If the account is using an explicit (custom) passphrase, the |
| 161 // bootstrap token will be derived from the most recently provided explicit | 247 // bootstrap token will be derived from the most recently provided explicit |
| 162 // passphrase (that was able to decrypt the data). | 248 // passphrase (that was able to decrypt the data). |
| 163 if (!nigori_has_explicit_passphrase) { | 249 if (!IsExplicitPassphrase(passphrase_type_)) { |
| 164 if (!cryptographer->has_pending_keys()) { | 250 if (!cryptographer->has_pending_keys()) { |
| 165 if (cryptographer->AddKey(key_params)) { | 251 if (cryptographer->AddKey(key_params)) { |
| 166 // Case 1 and 2. We set a new GAIA passphrase when there are no pending | 252 // 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 | 253 // keys (1), or overwriting an implicit passphrase with a new explicit |
| 168 // one (2) when there are no pending keys. | 254 // one (2) when there are no pending keys. |
| 169 DVLOG(1) << "Setting " << (is_explicit ? "explicit" : "implicit" ) | 255 if (is_explicit) { |
| 170 << " passphrase for encryption."; | 256 DVLOG(1) << "Setting explicit passphrase for encryption."; |
| 257 passphrase_type_ = CUSTOM_PASSPHRASE; | |
| 258 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, | |
| 259 OnPassphraseTypeChanged(passphrase_type_)); | |
| 260 } else { | |
| 261 DVLOG(1) << "Setting implicit passphrase for encryption."; | |
| 262 } | |
| 171 cryptographer->GetBootstrapToken(&bootstrap_token); | 263 cryptographer->GetBootstrapToken(&bootstrap_token); |
| 172 success = true; | 264 success = true; |
| 173 } else { | 265 } else { |
| 174 NOTREACHED() << "Failed to add key to cryptographer."; | 266 NOTREACHED() << "Failed to add key to cryptographer."; |
| 175 success = false; | 267 success = false; |
| 176 } | 268 } |
| 177 } else { // cryptographer->has_pending_keys() == true | 269 } else { // cryptographer->has_pending_keys() == true |
| 178 if (is_explicit) { | 270 if (is_explicit) { |
| 179 // This can only happen if the nigori node is updated with a new | 271 // 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 | 272 // 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); | 294 temp_cryptographer.GetBootstrapToken(&bootstrap_token); |
| 203 // We then set the new passphrase as the default passphrase of the | 295 // We then set the new passphrase as the default passphrase of the |
| 204 // real cryptographer, even though we have pending keys. This is safe, | 296 // real cryptographer, even though we have pending keys. This is safe, |
| 205 // as although Cryptographer::is_initialized() will now be true, | 297 // as although Cryptographer::is_initialized() will now be true, |
| 206 // is_ready() will remain false due to having pending keys. | 298 // is_ready() will remain false due to having pending keys. |
| 207 cryptographer->AddKey(key_params); | 299 cryptographer->AddKey(key_params); |
| 208 success = false; | 300 success = false; |
| 209 } | 301 } |
| 210 } // is_explicit | 302 } // is_explicit |
| 211 } // cryptographer->has_pending_keys() | 303 } // cryptographer->has_pending_keys() |
| 212 } else { // nigori_has_explicit_passphrase == true | 304 } else { // IsExplicitPassphrase(passphrase_type_) == true. |
| 213 // Case 6. We do not want to override a previously set explicit passphrase, | 305 // Case 6. We do not want to override a previously set explicit passphrase, |
| 214 // so we return a failure. | 306 // so we return a failure. |
| 215 DVLOG(1) << "Failing because an explicit passphrase is already set."; | 307 DVLOG(1) << "Failing because an explicit passphrase is already set."; |
| 216 success = false; | 308 success = false; |
| 217 } | 309 } |
| 218 | 310 |
| 219 DVLOG_IF(1, !success) | 311 DVLOG_IF(1, !success) |
| 220 << "Failure in SetEncryptionPassphrase; notifying and returning."; | 312 << "Failure in SetEncryptionPassphrase; notifying and returning."; |
| 221 DVLOG_IF(1, success) | 313 DVLOG_IF(1, success) |
| 222 << "Successfully set encryption passphrase; updating nigori and " | 314 << "Successfully set encryption passphrase; updating nigori and " |
| 223 "reencrypting."; | 315 "reencrypting."; |
| 224 | 316 |
| 225 FinishSetPassphrase( | 317 FinishSetPassphrase(success, bootstrap_token, &trans, &node); |
| 226 success, bootstrap_token, is_explicit, &trans, &node); | |
| 227 } | 318 } |
| 228 | 319 |
| 229 void SyncEncryptionHandlerImpl::SetDecryptionPassphrase( | 320 void SyncEncryptionHandlerImpl::SetDecryptionPassphrase( |
| 230 const std::string& passphrase) { | 321 const std::string& passphrase) { |
| 231 DCHECK(thread_checker_.CalledOnValidThread()); | 322 DCHECK(thread_checker_.CalledOnValidThread()); |
| 232 // We do not accept empty passphrases. | 323 // We do not accept empty passphrases. |
| 233 if (passphrase.empty()) { | 324 if (passphrase.empty()) { |
| 234 NOTREACHED() << "Cannot decrypt with an empty passphrase."; | 325 NOTREACHED() << "Cannot decrypt with an empty passphrase."; |
| 235 return; | 326 return; |
| 236 } | 327 } |
| 237 | 328 |
| 238 // All accesses to the cryptographer are protected by a transaction. | 329 // All accesses to the cryptographer are protected by a transaction. |
| 239 WriteTransaction trans(FROM_HERE, user_share_); | 330 WriteTransaction trans(FROM_HERE, user_share_); |
| 240 KeyParams key_params = {"localhost", "dummy", passphrase}; | 331 KeyParams key_params = {"localhost", "dummy", passphrase}; |
| 241 WriteNode node(&trans); | 332 WriteNode node(&trans); |
| 242 if (node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK) { | 333 if (node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK) { |
| 243 NOTREACHED(); | 334 NOTREACHED(); |
| 244 return; | 335 return; |
| 245 } | 336 } |
| 246 | 337 |
| 338 // Once we've migrated to keystore, we're only ever decrypting keys derived | |
| 339 // from an explicit passphrase. But, for clients without a keystore key yet | |
| 340 // (either not on by default or failed to download one), we still support | |
| 341 // decrypting with a gaia passphrase, and therefore bypass the | |
| 342 // DecryptExplicitPassphrase logic. | |
| 343 if (IsNigoriMigratedToKeystore(node.GetNigoriSpecifics()) && | |
| 344 IsExplicitPassphrase(passphrase_type_)) { | |
| 345 DecryptPendingKeysWithExplicitPassphrase(passphrase, &trans, &node); | |
| 346 return; | |
| 347 } | |
| 348 | |
| 247 Cryptographer* cryptographer = | 349 Cryptographer* cryptographer = |
| 248 &UnlockVaultMutable(trans.GetWrappedTrans())->cryptographer; | 350 &UnlockVaultMutable(trans.GetWrappedTrans())->cryptographer; |
| 249 if (!cryptographer->has_pending_keys()) { | 351 if (!cryptographer->has_pending_keys()) { |
| 250 // Note that this *can* happen in a rare situation where data is | 352 // Note that this *can* happen in a rare situation where data is |
| 251 // re-encrypted on another client while a SetDecryptionPassphrase() call is | 353 // 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. | 354 // 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 " | 355 NOTREACHED() << "Attempt to set decryption passphrase failed because there " |
| 254 << "were no pending keys."; | 356 << "were no pending keys."; |
| 255 return; | 357 return; |
| 256 } | 358 } |
| 257 | 359 |
| 258 bool nigori_has_explicit_passphrase = | |
| 259 node.GetNigoriSpecifics().using_explicit_passphrase(); | |
| 260 std::string bootstrap_token; | 360 std::string bootstrap_token; |
| 261 sync_pb::EncryptedData pending_keys; | 361 sync_pb::EncryptedData pending_keys; |
| 262 pending_keys = cryptographer->GetPendingKeys(); | 362 pending_keys = cryptographer->GetPendingKeys(); |
| 263 bool success = false; | 363 bool success = false; |
| 264 | 364 |
| 265 // There are three cases to handle here: | 365 // There are three cases to handle here: |
| 266 // 7. We're using the current GAIA password to decrypt the pending keys. This | 366 // 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 | 367 // happens when signing in to an account with a previously set implicit |
| 268 // passphrase, where the data is already encrypted with the newest GAIA | 368 // passphrase, where the data is already encrypted with the newest GAIA |
| 269 // password. | 369 // password. |
| 270 // 8. The user is providing an old GAIA password to decrypt the pending keys. | 370 // 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 | 371 // In this case, the user is using an implicit passphrase, but has changed |
| 272 // their password since they last encrypted their data, and therefore | 372 // their password since they last encrypted their data, and therefore |
| 273 // their current GAIA password was unable to decrypt the data. This will | 373 // 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 | 374 // happen when the user is setting up a new profile with a previously |
| 275 // encrypted account (after changing passwords). | 375 // encrypted account (after changing passwords). |
| 276 // 9. The user is providing a previously set explicit passphrase to decrypt | 376 // 9. The user is providing a previously set explicit passphrase to decrypt |
| 277 // the pending keys. | 377 // the pending keys. |
| 278 if (!nigori_has_explicit_passphrase) { | 378 if (!IsExplicitPassphrase(passphrase_type_)) { |
| 279 if (cryptographer->is_initialized()) { | 379 if (cryptographer->is_initialized()) { |
| 280 // We only want to change the default encryption key to the pending | 380 // We only want to change the default encryption key to the pending |
| 281 // one if the pending keybag already contains the current default. | 381 // one if the pending keybag already contains the current default. |
| 282 // This covers the case where a different client re-encrypted | 382 // This covers the case where a different client re-encrypted |
| 283 // everything with a newer gaia passphrase (and hence the keybag | 383 // everything with a newer gaia passphrase (and hence the keybag |
| 284 // contains keys from all previously used gaia passphrases). | 384 // contains keys from all previously used gaia passphrases). |
| 285 // Otherwise, we're in a situation where the pending keys are | 385 // Otherwise, we're in a situation where the pending keys are |
| 286 // encrypted with an old gaia passphrase, while the default is the | 386 // encrypted with an old gaia passphrase, while the default is the |
| 287 // current gaia passphrase. In that case, we preserve the default. | 387 // current gaia passphrase. In that case, we preserve the default. |
| 288 Cryptographer temp_cryptographer(cryptographer->encryptor()); | 388 Cryptographer temp_cryptographer(cryptographer->encryptor()); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 355 success = false; | 455 success = false; |
| 356 } | 456 } |
| 357 } // nigori_has_explicit_passphrase | 457 } // nigori_has_explicit_passphrase |
| 358 | 458 |
| 359 DVLOG_IF(1, !success) | 459 DVLOG_IF(1, !success) |
| 360 << "Failure in SetDecryptionPassphrase; notifying and returning."; | 460 << "Failure in SetDecryptionPassphrase; notifying and returning."; |
| 361 DVLOG_IF(1, success) | 461 DVLOG_IF(1, success) |
| 362 << "Successfully set decryption passphrase; updating nigori and " | 462 << "Successfully set decryption passphrase; updating nigori and " |
| 363 "reencrypting."; | 463 "reencrypting."; |
| 364 | 464 |
| 365 FinishSetPassphrase(success, | 465 FinishSetPassphrase(success, bootstrap_token, &trans, &node); |
| 366 bootstrap_token, | |
| 367 nigori_has_explicit_passphrase, | |
| 368 &trans, | |
| 369 &node); | |
| 370 } | 466 } |
| 371 | 467 |
| 372 void SyncEncryptionHandlerImpl::EnableEncryptEverything() { | 468 void SyncEncryptionHandlerImpl::EnableEncryptEverything() { |
| 373 DCHECK(thread_checker_.CalledOnValidThread()); | 469 DCHECK(thread_checker_.CalledOnValidThread()); |
| 374 WriteTransaction trans(FROM_HERE, user_share_); | 470 WriteTransaction trans(FROM_HERE, user_share_); |
| 375 ModelTypeSet* encrypted_types = | 471 DVLOG(1) << "Enabling encrypt everything."; |
| 376 &UnlockVaultMutable(trans.GetWrappedTrans())->encrypted_types; | 472 if (encrypt_everything_) |
| 377 if (encrypt_everything_) { | |
| 378 DCHECK(encrypted_types->Equals(ModelTypeSet::All())); | |
| 379 return; | 473 return; |
| 380 } | 474 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); | 475 WriteEncryptionStateToNigori(&trans); |
| 390 if (UnlockVault(trans.GetWrappedTrans()).cryptographer.is_ready()) | 476 if (UnlockVault(trans.GetWrappedTrans()).cryptographer.is_ready()) |
| 391 ReEncryptEverything(&trans); | 477 ReEncryptEverything(&trans); |
| 392 } | 478 } |
| 393 | 479 |
| 394 bool SyncEncryptionHandlerImpl::EncryptEverythingEnabled() const { | 480 bool SyncEncryptionHandlerImpl::EncryptEverythingEnabled() const { |
| 395 DCHECK(thread_checker_.CalledOnValidThread()); | 481 DCHECK(thread_checker_.CalledOnValidThread()); |
| 396 return encrypt_everything_; | 482 return encrypt_everything_; |
| 397 } | 483 } |
| 398 | 484 |
| 399 PassphraseState SyncEncryptionHandlerImpl::GetPassphraseState() const { | 485 PassphraseType SyncEncryptionHandlerImpl::GetPassphraseType() const { |
| 400 DCHECK(thread_checker_.CalledOnValidThread()); | 486 DCHECK(thread_checker_.CalledOnValidThread()); |
| 401 return passphrase_state_; | 487 return passphrase_type_; |
| 402 } | 488 } |
| 403 | 489 |
| 404 // Note: this is called from within a syncable transaction, so we need to post | 490 // Note: this is called from within a syncable transaction, so we need to post |
| 405 // tasks if we want to do any work that creates a new sync_api transaction. | 491 // tasks if we want to do any work that creates a new sync_api transaction. |
| 406 void SyncEncryptionHandlerImpl::ApplyNigoriUpdate( | 492 void SyncEncryptionHandlerImpl::ApplyNigoriUpdate( |
| 407 const sync_pb::NigoriSpecifics& nigori, | 493 const sync_pb::NigoriSpecifics& nigori, |
| 408 syncable::BaseTransaction* const trans) { | 494 syncable::BaseTransaction* const trans) { |
| 409 DCHECK(thread_checker_.CalledOnValidThread()); | 495 DCHECK(thread_checker_.CalledOnValidThread()); |
| 410 DCHECK(trans); | 496 DCHECK(trans); |
| 411 if (!ApplyNigoriUpdateImpl(nigori, trans)) { | 497 if (!ApplyNigoriUpdateImpl(nigori, trans)) { |
| 412 MessageLoop::current()->PostTask( | 498 MessageLoop::current()->PostTask( |
| 413 FROM_HERE, | 499 FROM_HERE, |
| 414 base::Bind(&SyncEncryptionHandlerImpl::RewriteNigori, | 500 base::Bind(&SyncEncryptionHandlerImpl::RewriteNigori, |
| 415 weak_ptr_factory_.GetWeakPtr())); | 501 weak_ptr_factory_.GetWeakPtr())); |
| 416 } | 502 } |
| 417 | 503 |
| 418 FOR_EACH_OBSERVER( | 504 FOR_EACH_OBSERVER( |
| 419 SyncEncryptionHandler::Observer, | 505 SyncEncryptionHandler::Observer, |
| 420 observers_, | 506 observers_, |
| 421 OnCryptographerStateChanged( | 507 OnCryptographerStateChanged( |
| 422 &UnlockVaultMutable(trans)->cryptographer)); | 508 &UnlockVaultMutable(trans)->cryptographer)); |
| 423 } | 509 } |
| 424 | 510 |
| 425 void SyncEncryptionHandlerImpl::UpdateNigoriFromEncryptedTypes( | 511 void SyncEncryptionHandlerImpl::UpdateNigoriFromEncryptedTypes( |
| 426 sync_pb::NigoriSpecifics* nigori, | 512 sync_pb::NigoriSpecifics* nigori, |
| 427 syncable::BaseTransaction* const trans) const { | 513 syncable::BaseTransaction* const trans) const { |
| 514 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 428 syncable::UpdateNigoriFromEncryptedTypes(UnlockVault(trans).encrypted_types, | 515 syncable::UpdateNigoriFromEncryptedTypes(UnlockVault(trans).encrypted_types, |
| 429 encrypt_everything_, | 516 encrypt_everything_, |
| 430 nigori); | 517 nigori); |
| 431 } | 518 } |
| 432 | 519 |
| 433 bool SyncEncryptionHandlerImpl::NeedKeystoreKey( | 520 bool SyncEncryptionHandlerImpl::NeedKeystoreKey( |
| 434 syncable::BaseTransaction* const trans) const { | 521 syncable::BaseTransaction* const trans) const { |
| 522 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 435 return keystore_key_.empty(); | 523 return keystore_key_.empty(); |
| 436 } | 524 } |
| 437 | 525 |
| 438 bool SyncEncryptionHandlerImpl::SetKeystoreKey( | 526 bool SyncEncryptionHandlerImpl::SetKeystoreKey( |
| 439 const std::string& key, | 527 const std::string& key, |
| 440 syncable::BaseTransaction* const trans) { | 528 syncable::BaseTransaction* const trans) { |
| 529 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 441 if (!keystore_key_.empty() || key.empty()) | 530 if (!keystore_key_.empty() || key.empty()) |
| 442 return false; | 531 return false; |
| 443 keystore_key_ = key; | 532 keystore_key_ = key; |
| 444 | 533 |
| 445 // TODO(zea): trigger migration if necessary. | |
| 446 | |
| 447 DVLOG(1) << "Keystore bootstrap token updated."; | 534 DVLOG(1) << "Keystore bootstrap token updated."; |
| 448 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, | 535 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, |
| 449 OnBootstrapTokenUpdated(key, | 536 OnBootstrapTokenUpdated(key, |
| 450 KEYSTORE_BOOTSTRAP_TOKEN)); | 537 KEYSTORE_BOOTSTRAP_TOKEN)); |
| 538 | |
| 539 Cryptographer* cryptographer = &UnlockVaultMutable(trans)->cryptographer; | |
| 540 syncable::Entry entry(trans, syncable::GET_BY_SERVER_TAG, kNigoriTag); | |
| 541 if (entry.good()) { | |
| 542 const sync_pb::NigoriSpecifics& nigori = | |
| 543 entry.Get(syncable::SPECIFICS).nigori(); | |
| 544 if (cryptographer->has_pending_keys() && | |
| 545 IsNigoriMigratedToKeystore(nigori) && | |
| 546 !nigori.keystore_decryptor().blob().empty()) { | |
| 547 // If the nigori is already migrated and we have pending keys, we might | |
| 548 // be able to decrypt them using the keystore decryptor. | |
| 549 DecryptPendingKeysWithKeystoreKey(keystore_key_, | |
| 550 nigori.keystore_decryptor(), | |
| 551 cryptographer); | |
| 552 } else if (ShouldTriggerMigration(nigori, *cryptographer)) { | |
| 553 // We call rewrite nigori to attempt to trigger migration. | |
| 554 // Need to post a task to open a new sync_api transaction. | |
| 555 MessageLoop::current()->PostTask( | |
| 556 FROM_HERE, | |
| 557 base::Bind(&SyncEncryptionHandlerImpl::RewriteNigori, | |
| 558 weak_ptr_factory_.GetWeakPtr())); | |
| 559 } | |
| 560 } | |
| 561 | |
| 451 return true; | 562 return true; |
| 452 } | 563 } |
| 453 | 564 |
| 454 ModelTypeSet SyncEncryptionHandlerImpl::GetEncryptedTypes( | 565 ModelTypeSet SyncEncryptionHandlerImpl::GetEncryptedTypes( |
| 455 syncable::BaseTransaction* const trans) const { | 566 syncable::BaseTransaction* const trans) const { |
| 456 return UnlockVault(trans).encrypted_types; | 567 return UnlockVault(trans).encrypted_types; |
| 457 } | 568 } |
| 458 | 569 |
| 459 Cryptographer* SyncEncryptionHandlerImpl::GetCryptographerUnsafe() { | 570 Cryptographer* SyncEncryptionHandlerImpl::GetCryptographerUnsafe() { |
| 460 DCHECK(thread_checker_.CalledOnValidThread()); | 571 DCHECK(thread_checker_.CalledOnValidThread()); |
| 461 return &vault_unsafe_.cryptographer; | 572 return &vault_unsafe_.cryptographer; |
| 462 } | 573 } |
| 463 | 574 |
| 464 ModelTypeSet SyncEncryptionHandlerImpl::GetEncryptedTypesUnsafe() { | 575 ModelTypeSet SyncEncryptionHandlerImpl::GetEncryptedTypesUnsafe() { |
| 465 DCHECK(thread_checker_.CalledOnValidThread()); | 576 DCHECK(thread_checker_.CalledOnValidThread()); |
| 466 return vault_unsafe_.encrypted_types; | 577 return vault_unsafe_.encrypted_types; |
| 467 } | 578 } |
| 468 | 579 |
| 580 bool SyncEncryptionHandlerImpl::MigratedToKeystore() { | |
| 581 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 582 ReadTransaction trans(FROM_HERE, user_share_); | |
| 583 ReadNode nigori_node(&trans); | |
| 584 if (nigori_node.InitByTagLookup(kNigoriTag) != BaseNode::INIT_OK) | |
| 585 return false; | |
| 586 return IsNigoriMigratedToKeystore(nigori_node.GetNigoriSpecifics()); | |
| 587 } | |
| 588 | |
| 469 // This function iterates over all encrypted types. There are many scenarios in | 589 // 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, | 590 // 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 | 591 // the lookup of the root node will fail and we will skip encryption for that |
| 472 // type. | 592 // type. |
| 473 void SyncEncryptionHandlerImpl::ReEncryptEverything( | 593 void SyncEncryptionHandlerImpl::ReEncryptEverything( |
| 474 WriteTransaction* trans) { | 594 WriteTransaction* trans) { |
| 475 DCHECK(thread_checker_.CalledOnValidThread()); | 595 DCHECK(thread_checker_.CalledOnValidThread()); |
| 476 DCHECK(UnlockVault(trans->GetWrappedTrans()).cryptographer.is_ready()); | 596 DCHECK(UnlockVault(trans->GetWrappedTrans()).cryptographer.is_ready()); |
| 477 for (ModelTypeSet::Iterator iter = | 597 for (ModelTypeSet::Iterator iter = |
| 478 UnlockVault(trans->GetWrappedTrans()).encrypted_types.First(); | 598 UnlockVault(trans->GetWrappedTrans()).encrypted_types.First(); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 537 OnEncryptionComplete()); | 657 OnEncryptionComplete()); |
| 538 } | 658 } |
| 539 | 659 |
| 540 bool SyncEncryptionHandlerImpl::ApplyNigoriUpdateImpl( | 660 bool SyncEncryptionHandlerImpl::ApplyNigoriUpdateImpl( |
| 541 const sync_pb::NigoriSpecifics& nigori, | 661 const sync_pb::NigoriSpecifics& nigori, |
| 542 syncable::BaseTransaction* const trans) { | 662 syncable::BaseTransaction* const trans) { |
| 543 DCHECK(thread_checker_.CalledOnValidThread()); | 663 DCHECK(thread_checker_.CalledOnValidThread()); |
| 544 DVLOG(1) << "Applying nigori node update."; | 664 DVLOG(1) << "Applying nigori node update."; |
| 545 bool nigori_types_need_update = !UpdateEncryptedTypesFromNigori(nigori, | 665 bool nigori_types_need_update = !UpdateEncryptedTypesFromNigori(nigori, |
| 546 trans); | 666 trans); |
| 547 if (nigori.using_explicit_passphrase() && | 667 bool is_nigori_migrated = IsNigoriMigratedToKeystore(nigori); |
| 548 passphrase_state_ != CUSTOM_PASSPHRASE) { | 668 if (is_nigori_migrated) { |
| 549 passphrase_state_ = CUSTOM_PASSPHRASE; | 669 migration_time_ms_ = nigori.keystore_migration_time(); |
| 550 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, | 670 PassphraseType nigori_passphrase_type = |
| 551 OnPassphraseStateChanged(passphrase_state_)); | 671 ProtoPassphraseTypeToEnum(nigori.passphrase_type()); |
| 672 | |
| 673 // Only update the local passphrase state if it's a valid transition: | |
| 674 // - implicit -> keystore | |
| 675 // - implicit -> frozen implicit | |
| 676 // - implicit -> custom | |
| 677 // - keystore -> custom | |
| 678 if (passphrase_type_ != nigori_passphrase_type && | |
| 679 nigori_passphrase_type != IMPLICIT_PASSPHRASE && | |
| 680 (passphrase_type_ == IMPLICIT_PASSPHRASE || | |
| 681 nigori_passphrase_type == CUSTOM_PASSPHRASE)) { | |
|
tim (not reviewing)
2012/09/10 20:41:52
in theory passphrase_type_ = frozen implicit can s
Nicolas Zea
2012/09/11 14:21:31
I actually think that's okay. This leaves some roo
| |
| 682 DVLOG(1) << "Changing passphrase state from " | |
| 683 << PassphraseTypeToString(passphrase_type_) | |
| 684 << " to " | |
| 685 << PassphraseTypeToString(nigori_passphrase_type); | |
| 686 passphrase_type_ = nigori_passphrase_type; | |
| 687 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, | |
| 688 OnPassphraseTypeChanged(passphrase_type_)); | |
| 689 } | |
| 690 if (passphrase_type_ == KEYSTORE_PASSPHRASE && encrypt_everything_) { | |
| 691 DVLOG(1) << "Changing passphrase state to FROZEN_IMPLICIT_PASSPHRASE " | |
| 692 << "due to full encryption."; | |
|
tim (not reviewing)
2012/09/10 20:41:52
I think a comment here explaining that this is eff
Nicolas Zea
2012/09/11 14:21:31
Done.
| |
| 693 passphrase_type_ = FROZEN_IMPLICIT_PASSPHRASE; | |
| 694 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, | |
| 695 OnPassphraseTypeChanged(passphrase_type_)); | |
| 696 } | |
| 697 } else { | |
| 698 // It's possible that while we're waiting for migration another old | |
|
tim (not reviewing)
2012/09/10 20:41:52
"another old client"... what does 'old' mean here?
Nicolas Zea
2012/09/11 14:21:31
Old client means those that do not have keystore e
| |
| 699 // client enables a custom passphrase. | |
| 700 if (nigori.frozen_keybag() && | |
|
tim (not reviewing)
2012/09/10 20:41:52
can we call this keybag_is_frozen()? Everytime I
Nicolas Zea
2012/09/11 14:21:31
Done.
| |
| 701 passphrase_type_ != CUSTOM_PASSPHRASE) { | |
| 702 passphrase_type_ = CUSTOM_PASSPHRASE; | |
|
tim (not reviewing)
2012/09/10 20:41:52
before setting, can we DCHECK that passphrase_type
Nicolas Zea
2012/09/11 14:21:31
That dcheck might fire due to nigori races. We han
| |
| 703 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, | |
| 704 OnPassphraseTypeChanged(passphrase_type_)); | |
| 705 } | |
| 552 } | 706 } |
| 553 | 707 |
| 554 Cryptographer* cryptographer = &UnlockVaultMutable(trans)->cryptographer; | 708 Cryptographer* cryptographer = &UnlockVaultMutable(trans)->cryptographer; |
| 555 bool nigori_needs_new_keys = false; | 709 bool nigori_needs_new_keys = false; |
| 556 if (!nigori.encrypted().blob().empty()) { | 710 if (!nigori.encryption_keybag().blob().empty()) { |
| 557 if (cryptographer->CanDecrypt(nigori.encrypted())) { | 711 // We only update the default passphrase if this was a new explicit |
|
tim (not reviewing)
2012/09/10 20:41:52
nit - '...update the default key...' / need_new_de
| |
| 558 cryptographer->InstallKeys(nigori.encrypted()); | 712 // 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 | 713 // key. |
| 560 // passphrase. Else, since it was decryptable, it must not have been a new | 714 bool need_new_default = false; |
| 561 // key. | 715 if (is_nigori_migrated) { |
| 562 if (nigori.using_explicit_passphrase()) | 716 need_new_default = IsExplicitPassphrase( |
| 563 cryptographer->SetDefaultKey(nigori.encrypted().key_name()); | 717 ProtoPassphraseTypeToEnum(nigori.passphrase_type())); |
| 564 | |
| 565 // Check if the cryptographer's keybag is newer than the nigori's | |
| 566 // keybag. If so, we need to overwrite the nigori node. | |
| 567 sync_pb::EncryptedData new_keys = nigori.encrypted(); | |
| 568 if (!cryptographer->GetKeys(&new_keys)) | |
| 569 NOTREACHED(); | |
| 570 if (nigori.encrypted().SerializeAsString() != | |
| 571 new_keys.SerializeAsString()) | |
| 572 nigori_needs_new_keys = true; | |
| 573 } else { | 718 } else { |
| 574 cryptographer->SetPendingKeys(nigori.encrypted()); | 719 need_new_default = nigori.frozen_keybag(); |
| 720 } | |
| 721 if (!AttemptToInstallKeybag(nigori.encryption_keybag(), | |
| 722 need_new_default, | |
| 723 cryptographer)) { | |
| 724 // Check to see if we can decrypt the keybag using the keystore decryptor. | |
| 725 cryptographer->SetPendingKeys(nigori.encryption_keybag()); | |
| 726 if (!nigori.keystore_decryptor().blob().empty() && | |
| 727 !keystore_key_.empty()) { | |
| 728 if (DecryptPendingKeysWithKeystoreKey(keystore_key_, | |
| 729 nigori.keystore_decryptor(), | |
| 730 cryptographer)) { | |
| 731 nigori_needs_new_keys = | |
| 732 cryptographer->KeybagIsStale(nigori.encryption_keybag()); | |
| 733 } else { | |
| 734 LOG(ERROR) << "Failed to decrypt pending keys using keystore " | |
| 735 << "bootstrap key."; | |
|
tim (not reviewing)
2012/09/10 20:41:52
Can we surface this somehow? Is it a LOG(ERROR) be
Nicolas Zea
2012/09/11 14:21:31
Right, if we failed to decrypt a keystore decrypto
| |
| 736 } | |
| 737 } | |
| 738 } else { | |
| 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_type_matches = true; |
| 600 if (nigori.using_explicit_passphrase() != explicit_passphrase || | 772 if (!is_nigori_migrated) { |
| 773 DCHECK(passphrase_type_ == CUSTOM_PASSPHRASE || | |
| 774 passphrase_type_ == IMPLICIT_PASSPHRASE); | |
| 775 passphrase_type_matches = | |
| 776 nigori.frozen_keybag() == IsExplicitPassphrase(passphrase_type_); | |
| 777 } else { | |
| 778 passphrase_type_matches = | |
| 779 (ProtoPassphraseTypeToEnum(nigori.passphrase_type()) == | |
| 780 passphrase_type_); | |
| 781 } | |
| 782 if (!passphrase_type_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 DCHECK(IsNigoriMigratedToKeystore(nigori_node->GetNigoriSpecifics())); | |
| 891 KeyParams key_params = {"localhost", "dummy", passphrase}; | |
| 892 | |
| 893 if (passphrase_type_ != KEYSTORE_PASSPHRASE) { | |
| 894 DVLOG(1) << "Failing to set a custom passphrase because one has already " | |
| 895 << "been set."; | |
| 896 FinishSetPassphrase(false, "", trans, nigori_node); | |
| 897 return; | |
| 898 } | |
| 899 | |
| 900 Cryptographer* cryptographer = | |
| 901 &UnlockVaultMutable(trans->GetWrappedTrans())->cryptographer; | |
| 902 if (cryptographer->has_pending_keys()) { | |
| 903 // This theoretically shouldn't happen, because the only way to have pending | |
| 904 // keys after migrating to keystore support is if a custom passphrase was | |
| 905 // set, which should update passpshrase_state_ and should be caught by the | |
| 906 // if statement above. For the sake of safety though, we check for it in | |
| 907 // case a client is misbehaving. | |
| 908 LOG(ERROR) << "Failing to set custom passphrase because of pending keys."; | |
| 909 FinishSetPassphrase(false, "", trans, nigori_node); | |
| 910 return; | |
| 911 } | |
| 912 | |
| 913 std::string bootstrap_token; | |
| 914 if (cryptographer->AddKey(key_params)) { | |
| 915 DVLOG(1) << "Setting custom passphrase."; | |
| 916 cryptographer->GetBootstrapToken(&bootstrap_token); | |
| 917 passphrase_type_ = CUSTOM_PASSPHRASE; | |
| 918 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, | |
| 919 OnPassphraseTypeChanged(passphrase_type_)); | |
| 920 } else { | |
| 921 NOTREACHED() << "Failed to add key to cryptographer."; | |
| 922 return; | |
| 923 } | |
| 924 FinishSetPassphrase(true, bootstrap_token, trans, nigori_node); | |
| 925 } | |
| 926 | |
| 927 void SyncEncryptionHandlerImpl::DecryptPendingKeysWithExplicitPassphrase( | |
| 928 const std::string& passphrase, | |
| 929 WriteTransaction* trans, | |
| 930 WriteNode* nigori_node) { | |
| 931 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 932 DCHECK(IsExplicitPassphrase(passphrase_type_)); | |
| 933 KeyParams key_params = {"localhost", "dummy", passphrase}; | |
| 934 | |
| 935 Cryptographer* cryptographer = | |
| 936 &UnlockVaultMutable(trans->GetWrappedTrans())->cryptographer; | |
| 937 if (!cryptographer->has_pending_keys()) { | |
| 938 // Note that this *can* happen in a rare situation where data is | |
| 939 // re-encrypted on another client while a SetDecryptionPassphrase() call is | |
| 940 // in-flight on this client. It is rare enough that we choose to do nothing. | |
| 941 NOTREACHED() << "Attempt to set decryption passphrase failed because there " | |
| 942 << "were no pending keys."; | |
| 943 return; | |
| 944 } | |
| 945 | |
| 946 DCHECK(IsExplicitPassphrase(passphrase_type_)); | |
| 947 bool success = false; | |
| 948 std::string bootstrap_token; | |
| 949 if (cryptographer->DecryptPendingKeys(key_params)) { | |
| 950 DVLOG(1) << "Explicit passphrase accepted for decryption."; | |
| 951 cryptographer->GetBootstrapToken(&bootstrap_token); | |
| 952 success = true; | |
| 953 } else { | |
| 954 DVLOG(1) << "Explicit passphrase failed to decrypt."; | |
| 955 success = false; | |
| 956 } | |
| 957 if (success && !keystore_key_.empty()) { | |
| 958 // Should already be part of the encryption keybag, but we add it just | |
| 959 // in case. | |
| 960 KeyParams key_params = {"localhost", "dummy", keystore_key_}; | |
| 961 cryptographer->AddNonDefaultKey(key_params); | |
| 962 } | |
| 963 FinishSetPassphrase(success, bootstrap_token, trans, nigori_node); | |
| 964 } | |
| 965 | |
| 699 void SyncEncryptionHandlerImpl::FinishSetPassphrase( | 966 void SyncEncryptionHandlerImpl::FinishSetPassphrase( |
| 700 bool success, | 967 bool success, |
| 701 const std::string& bootstrap_token, | 968 const std::string& bootstrap_token, |
| 702 bool is_explicit, | |
| 703 WriteTransaction* trans, | 969 WriteTransaction* trans, |
| 704 WriteNode* nigori_node) { | 970 WriteNode* nigori_node) { |
| 705 DCHECK(thread_checker_.CalledOnValidThread()); | 971 DCHECK(thread_checker_.CalledOnValidThread()); |
| 706 FOR_EACH_OBSERVER( | 972 FOR_EACH_OBSERVER( |
| 707 SyncEncryptionHandler::Observer, | 973 SyncEncryptionHandler::Observer, |
| 708 observers_, | 974 observers_, |
| 709 OnCryptographerStateChanged( | 975 OnCryptographerStateChanged( |
| 710 &UnlockVaultMutable(trans->GetWrappedTrans())->cryptographer)); | 976 &UnlockVaultMutable(trans->GetWrappedTrans())->cryptographer)); |
| 711 | 977 |
| 712 // It's possible we need to change the bootstrap token even if we failed to | 978 // It's possible we need to change the bootstrap token even if we failed to |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 729 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, | 995 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, |
| 730 OnPassphraseRequired(REASON_DECRYPTION, | 996 OnPassphraseRequired(REASON_DECRYPTION, |
| 731 cryptographer.GetPendingKeys())); | 997 cryptographer.GetPendingKeys())); |
| 732 } else { | 998 } else { |
| 733 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, | 999 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, |
| 734 OnPassphraseRequired(REASON_ENCRYPTION, | 1000 OnPassphraseRequired(REASON_ENCRYPTION, |
| 735 sync_pb::EncryptedData())); | 1001 sync_pb::EncryptedData())); |
| 736 } | 1002 } |
| 737 return; | 1003 return; |
| 738 } | 1004 } |
| 739 | 1005 DCHECK(success); |
| 740 DCHECK(cryptographer.is_ready()); | 1006 DCHECK(cryptographer.is_ready()); |
| 741 | 1007 |
| 742 // TODO(zea): trigger migration if necessary. | 1008 // Will do nothing if we're already properly migrated or unable to migrate. |
|
tim (not reviewing)
2012/09/10 20:41:52
"Will do nothing if we're already properly migrate
Nicolas Zea
2012/09/11 14:21:31
Done.
| |
| 1009 // Otherwise will update the nigori node with the current migrated state, | |
| 1010 // writing all encryption state as it does. | |
| 1011 if (!AttemptToMigrateNigoriToKeystore(trans, nigori_node)) { | |
| 1012 sync_pb::NigoriSpecifics nigori(nigori_node->GetNigoriSpecifics()); | |
| 1013 // Does not modify nigori.encryption_keybag() if the original decrypted | |
| 1014 // data was the same. | |
| 1015 if (!cryptographer.GetKeys(nigori.mutable_encryption_keybag())) | |
| 1016 NOTREACHED(); | |
| 1017 if (IsNigoriMigratedToKeystore(nigori)) { | |
| 1018 DCHECK(keystore_key_.empty() || IsExplicitPassphrase(passphrase_type_)); | |
| 1019 DVLOG(1) << "Leaving nigori migration state untouched after setting" | |
| 1020 << " passphrase."; | |
| 1021 } else { | |
| 1022 nigori.set_frozen_keybag( | |
| 1023 IsExplicitPassphrase(passphrase_type_)); | |
| 1024 } | |
| 1025 nigori_node->SetNigoriSpecifics(nigori); | |
| 1026 } | |
| 743 | 1027 |
| 744 sync_pb::NigoriSpecifics specifics(nigori_node->GetNigoriSpecifics()); | 1028 // Must do this after OnPassphraseTypeChanged, in order to ensure the PSS |
| 745 // Does not modify specifics.encrypted() if the original decrypted data was | |
| 746 // the same. | |
| 747 if (!cryptographer.GetKeys(specifics.mutable_encrypted())) | |
| 748 NOTREACHED(); | |
| 749 if (is_explicit && passphrase_state_ != CUSTOM_PASSPHRASE) { | |
| 750 passphrase_state_ = CUSTOM_PASSPHRASE; | |
| 751 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, | |
| 752 OnPassphraseStateChanged(passphrase_state_)); | |
| 753 } | |
| 754 specifics.set_using_explicit_passphrase(is_explicit); | |
| 755 nigori_node->SetNigoriSpecifics(specifics); | |
| 756 | |
| 757 // Must do this after OnPassphraseStateChanged, in order to ensure the PSS | |
| 758 // checks the passphrase state after it has been set. | 1029 // checks the passphrase state after it has been set. |
| 759 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, | 1030 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, |
| 760 OnPassphraseAccepted()); | 1031 OnPassphraseAccepted()); |
| 761 | 1032 |
| 762 // Does nothing if everything is already encrypted. | 1033 // Does nothing if everything is already encrypted. |
| 1034 // TODO(zea): If we just migrated and enabled encryption, this will be | |
| 1035 // redundant. Figure out a way to not do this unnecessarily. | |
| 763 ReEncryptEverything(trans); | 1036 ReEncryptEverything(trans); |
| 764 } | 1037 } |
| 765 | 1038 |
| 766 void SyncEncryptionHandlerImpl::MergeEncryptedTypes( | 1039 void SyncEncryptionHandlerImpl::MergeEncryptedTypes( |
| 767 ModelTypeSet new_encrypted_types, | 1040 ModelTypeSet new_encrypted_types, |
| 768 syncable::BaseTransaction* const trans) { | 1041 syncable::BaseTransaction* const trans) { |
| 769 DCHECK(thread_checker_.CalledOnValidThread()); | 1042 DCHECK(thread_checker_.CalledOnValidThread()); |
| 770 ModelTypeSet* encrypted_types = &UnlockVaultMutable(trans)->encrypted_types; | 1043 ModelTypeSet* encrypted_types = &UnlockVaultMutable(trans)->encrypted_types; |
| 771 if (!encrypted_types->HasAll(new_encrypted_types)) { | 1044 if (!encrypted_types->HasAll(new_encrypted_types)) { |
| 772 *encrypted_types = new_encrypted_types; | 1045 *encrypted_types = new_encrypted_types; |
| 773 FOR_EACH_OBSERVER( | 1046 FOR_EACH_OBSERVER( |
| 774 Observer, observers_, | 1047 Observer, observers_, |
| 775 OnEncryptedTypesChanged(*encrypted_types, encrypt_everything_)); | 1048 OnEncryptedTypesChanged(*encrypted_types, encrypt_everything_)); |
| 776 } | 1049 } |
| 777 } | 1050 } |
| 778 | 1051 |
| 779 SyncEncryptionHandlerImpl::Vault* SyncEncryptionHandlerImpl::UnlockVaultMutable( | 1052 SyncEncryptionHandlerImpl::Vault* SyncEncryptionHandlerImpl::UnlockVaultMutable( |
| 780 syncable::BaseTransaction* const trans) { | 1053 syncable::BaseTransaction* const trans) { |
| 781 DCHECK_EQ(user_share_->directory.get(), trans->directory()); | 1054 DCHECK_EQ(user_share_->directory.get(), trans->directory()); |
| 782 return &vault_unsafe_; | 1055 return &vault_unsafe_; |
| 783 } | 1056 } |
| 784 | 1057 |
| 785 const SyncEncryptionHandlerImpl::Vault& SyncEncryptionHandlerImpl::UnlockVault( | 1058 const SyncEncryptionHandlerImpl::Vault& SyncEncryptionHandlerImpl::UnlockVault( |
| 786 syncable::BaseTransaction* const trans) const { | 1059 syncable::BaseTransaction* const trans) const { |
| 787 DCHECK_EQ(user_share_->directory.get(), trans->directory()); | 1060 DCHECK_EQ(user_share_->directory.get(), trans->directory()); |
| 788 return vault_unsafe_; | 1061 return vault_unsafe_; |
| 789 } | 1062 } |
| 790 | 1063 |
| 1064 bool SyncEncryptionHandlerImpl::ShouldTriggerMigration( | |
| 1065 const sync_pb::NigoriSpecifics& nigori, | |
| 1066 const Cryptographer& cryptographer) const { | |
| 1067 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 1068 // TODO(zea): once we're willing to have the keystore key be the only | |
| 1069 // encryption key, change this to !has_pending_keys(). For now, we need the | |
| 1070 // cryptographer to be initialized with the current GAIA pass so that older | |
| 1071 // clients (that don't have keystore support) can decrypt the keybag. | |
| 1072 if (!cryptographer.is_ready()) | |
| 1073 return false; | |
| 1074 if (IsNigoriMigratedToKeystore(nigori)) { | |
| 1075 // If the nigori is already migrated but has an old passphrase state, | |
|
tim (not reviewing)
2012/09/10 20:41:52
What is an "old passphrase state"?
Nicolas Zea
2012/09/11 14:21:31
Rewritten to reflect that this is detecting a migr
| |
| 1076 // re-migrate. Similarly, if the nigori has an explicit passphrase but | |
| 1077 // does not have full encryption, or the nigori has an implicit passphrase | |
|
tim (not reviewing)
2012/09/10 20:41:52
"if the nigori has an explicit passphrase but does
Nicolas Zea
2012/09/11 14:21:31
Right. Noted that these cases are also detecting t
| |
| 1078 // but does have full encryption, re-migrate. | |
| 1079 if (passphrase_type_ != KEYSTORE_PASSPHRASE && | |
| 1080 nigori.passphrase_type() == | |
| 1081 sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE) { | |
| 1082 return true; | |
| 1083 } else if (IsExplicitPassphrase(passphrase_type_) && | |
| 1084 !encrypt_everything_) { | |
| 1085 return true; | |
| 1086 } else if (passphrase_type_ == KEYSTORE_PASSPHRASE && | |
| 1087 encrypt_everything_) { | |
| 1088 return true; | |
| 1089 } else { | |
| 1090 return false; | |
| 1091 } | |
| 1092 } else if (keystore_key_.empty()) { | |
| 1093 // If we haven't already migrated, we don't want to do anything unless | |
| 1094 // a keystore key is available (so that those clients without keystore | |
| 1095 // encryption enabled aren't forced into new states, e.g. frozen implicit | |
| 1096 // passphrase). | |
| 1097 return false; | |
| 1098 } | |
| 1099 return true; | |
| 1100 } | |
| 1101 | |
| 1102 bool SyncEncryptionHandlerImpl::AttemptToMigrateNigoriToKeystore( | |
| 1103 WriteTransaction* trans, | |
| 1104 WriteNode* nigori_node) { | |
| 1105 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 1106 const sync_pb::NigoriSpecifics& old_nigori = | |
| 1107 nigori_node->GetNigoriSpecifics(); | |
| 1108 Cryptographer* cryptographer = | |
| 1109 &UnlockVaultMutable(trans->GetWrappedTrans())->cryptographer; | |
| 1110 | |
| 1111 if (!ShouldTriggerMigration(old_nigori, *cryptographer)) | |
| 1112 return false; | |
| 1113 | |
| 1114 DVLOG(1) << "Starting nigori migration to keystore support."; | |
| 1115 if (migration_time_ms_ == 0) | |
| 1116 migration_time_ms_ = TimeToProtoTime(base::Time::Now()); | |
| 1117 sync_pb::NigoriSpecifics migrated_nigori(old_nigori); | |
| 1118 migrated_nigori.set_keystore_migration_time(migration_time_ms_); | |
|
tim (not reviewing)
2012/09/10 20:41:52
Should we be doing this before actually completing
Nicolas Zea
2012/09/11 14:21:31
Moved this down so that we don't set migration_tim
| |
| 1119 | |
| 1120 PassphraseType new_passphrase_type = passphrase_type_; | |
| 1121 bool new_encrypt_everything = encrypt_everything_; | |
| 1122 if (encrypt_everything_ && !IsExplicitPassphrase(passphrase_type_)) { | |
| 1123 DVLOG(1) << "Switching to frozen implicit passphrase due to already having " | |
| 1124 << "full encryption."; | |
| 1125 new_passphrase_type = FROZEN_IMPLICIT_PASSPHRASE; | |
| 1126 migrated_nigori.clear_keystore_decryptor(); | |
| 1127 } else if (IsExplicitPassphrase(passphrase_type_)) { | |
| 1128 DVLOG_IF(1, !encrypt_everything_) << "Enabling encrypt everything due to " | |
| 1129 << "explicit passphrase"; | |
| 1130 new_encrypt_everything = true; | |
| 1131 migrated_nigori.clear_keystore_decryptor(); | |
| 1132 } else { | |
| 1133 DCHECK_EQ(passphrase_type_, IMPLICIT_PASSPHRASE); | |
| 1134 DCHECK(!encrypt_everything_); | |
| 1135 new_passphrase_type = KEYSTORE_PASSPHRASE; | |
| 1136 DVLOG(1) << "Switching to keystore passphrase state."; | |
| 1137 } | |
| 1138 migrated_nigori.set_encrypt_everything(new_encrypt_everything); | |
| 1139 migrated_nigori.set_passphrase_type( | |
| 1140 EnumPassphraseTypeToProto(new_passphrase_type)); | |
| 1141 migrated_nigori.set_frozen_keybag(true); | |
| 1142 | |
| 1143 if (!keystore_key_.empty()) { | |
| 1144 KeyParams key_params = {"localhost", "dummy", keystore_key_}; | |
| 1145 if (!cryptographer->AddNonDefaultKey(key_params)) { | |
| 1146 LOG(ERROR) << "Failed to add keystore key as non-default key."; | |
| 1147 return false; | |
| 1148 } | |
| 1149 } | |
| 1150 if (new_passphrase_type == KEYSTORE_PASSPHRASE && | |
| 1151 !GetKeystoreDecryptor( | |
| 1152 *cryptographer, | |
| 1153 keystore_key_, | |
| 1154 migrated_nigori.mutable_keystore_decryptor())) { | |
| 1155 LOG(ERROR) << "Failed to extract keystore decryptor."; | |
| 1156 return false; | |
| 1157 } | |
| 1158 if (!cryptographer->GetKeys(migrated_nigori.mutable_encryption_keybag())) { | |
| 1159 LOG(ERROR) << "Failed to extract encryption keybag."; | |
| 1160 return false; | |
| 1161 } | |
| 1162 | |
| 1163 DVLOG(1) << "Completing nigori migration to keystore support."; | |
| 1164 nigori_node->SetNigoriSpecifics(migrated_nigori); | |
| 1165 if (passphrase_type_ != new_passphrase_type) { | |
| 1166 passphrase_type_ = new_passphrase_type; | |
| 1167 FOR_EACH_OBSERVER(SyncEncryptionHandler::Observer, observers_, | |
| 1168 OnPassphraseTypeChanged(passphrase_type_)); | |
| 1169 } | |
| 1170 if (new_encrypt_everything && !encrypt_everything_) { | |
| 1171 EnableEncryptEverythingImpl(trans->GetWrappedTrans()); | |
| 1172 ReEncryptEverything(trans); | |
| 1173 } | |
| 1174 return true; | |
| 1175 } | |
| 1176 | |
| 1177 bool SyncEncryptionHandlerImpl::GetKeystoreDecryptor( | |
| 1178 const Cryptographer& cryptographer, | |
| 1179 const std::string& keystore_key, | |
| 1180 sync_pb::EncryptedData* encrypted_blob) { | |
| 1181 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 1182 DCHECK(!keystore_key.empty()); | |
| 1183 DCHECK(cryptographer.is_ready()); | |
| 1184 std::string serialized_nigori; | |
| 1185 serialized_nigori = cryptographer.GetDefaultNigoriKey(); | |
| 1186 if (serialized_nigori.empty()) { | |
| 1187 LOG(ERROR) << "Failed to get cryptographer bootstrap token."; | |
| 1188 return false; | |
| 1189 } | |
| 1190 Cryptographer temp_cryptographer(cryptographer.encryptor()); | |
| 1191 KeyParams key_params = {"localhost", "dummy", keystore_key}; | |
| 1192 if (!temp_cryptographer.AddKey(key_params)) | |
| 1193 return false; | |
| 1194 if (!temp_cryptographer.EncryptString(serialized_nigori, encrypted_blob)) | |
| 1195 return false; | |
| 1196 return true; | |
| 1197 } | |
| 1198 | |
| 1199 bool SyncEncryptionHandlerImpl::AttemptToInstallKeybag( | |
| 1200 const sync_pb::EncryptedData& keybag, | |
| 1201 bool update_default, | |
| 1202 Cryptographer* cryptographer) { | |
| 1203 if (!cryptographer->CanDecrypt(keybag)) | |
| 1204 return false; | |
| 1205 cryptographer->InstallKeys(keybag); | |
| 1206 if (update_default) | |
| 1207 cryptographer->SetDefaultKey(keybag.key_name()); | |
| 1208 return true; | |
| 1209 } | |
| 1210 | |
| 1211 void SyncEncryptionHandlerImpl::EnableEncryptEverythingImpl( | |
| 1212 syncable::BaseTransaction* const trans) { | |
| 1213 ModelTypeSet* encrypted_types = &UnlockVaultMutable(trans)->encrypted_types; | |
| 1214 if (encrypt_everything_) { | |
| 1215 DCHECK(encrypted_types->Equals(ModelTypeSet::All())); | |
| 1216 return; | |
| 1217 } | |
| 1218 encrypt_everything_ = true; | |
| 1219 *encrypted_types = ModelTypeSet::All(); | |
| 1220 FOR_EACH_OBSERVER( | |
| 1221 Observer, observers_, | |
| 1222 OnEncryptedTypesChanged(*encrypted_types, encrypt_everything_)); | |
| 1223 } | |
| 1224 | |
| 1225 bool SyncEncryptionHandlerImpl::DecryptPendingKeysWithKeystoreKey( | |
| 1226 const std::string& keystore_key, | |
| 1227 const sync_pb::EncryptedData& keystore_decryptor, | |
| 1228 Cryptographer* cryptographer) { | |
| 1229 DCHECK(cryptographer->has_pending_keys()); | |
| 1230 if (keystore_decryptor.blob().empty()) | |
| 1231 return false; | |
| 1232 Cryptographer temp_cryptographer(cryptographer->encryptor()); | |
| 1233 KeyParams keystore_params = {"localhost", "dummy", keystore_key_}; | |
| 1234 if (temp_cryptographer.AddKey(keystore_params) && | |
| 1235 temp_cryptographer.CanDecrypt(keystore_decryptor)) { | |
| 1236 // Someone else migrated the nigori for us! How generous! Go ahead and | |
| 1237 // install both the keystore key and the new default encryption key | |
| 1238 // (i.e. the one provided by the keystore decryptor) into the | |
| 1239 // cryptographer. | |
| 1240 // The keystore decryptor is a keystore key encrypted blob containing | |
| 1241 // the current serialized default encryption key (and as such should be | |
| 1242 // able to decrypt the nigori node's encryption keybag). | |
| 1243 DVLOG(1) << "Attempting to decrypt pending keys using " | |
| 1244 << "keystore decryptor."; | |
| 1245 std::string serialized_nigori = | |
| 1246 temp_cryptographer.DecryptToString(keystore_decryptor); | |
| 1247 // This will decrypt the pending keys and add them if possible. The key | |
| 1248 // within |serialized_nigori| will be the default after. | |
| 1249 cryptographer->ImportNigoriKey(serialized_nigori); | |
| 1250 // Theoretically the encryption keybag should already contain the keystore | |
| 1251 // key. We explicitly add it as a safety measure. | |
| 1252 cryptographer->AddNonDefaultKey(keystore_params); | |
| 1253 if (cryptographer->is_ready()) { | |
| 1254 std::string bootstrap_token; | |
| 1255 cryptographer->GetBootstrapToken(&bootstrap_token); | |
| 1256 DVLOG(1) << "Keystore decryptor decrypted pending keys."; | |
| 1257 FOR_EACH_OBSERVER( | |
| 1258 SyncEncryptionHandler::Observer, | |
| 1259 observers_, | |
| 1260 OnBootstrapTokenUpdated(bootstrap_token, | |
| 1261 PASSPHRASE_BOOTSTRAP_TOKEN)); | |
| 1262 FOR_EACH_OBSERVER( | |
| 1263 SyncEncryptionHandler::Observer, | |
| 1264 observers_, | |
| 1265 OnCryptographerStateChanged(cryptographer)); | |
| 1266 return true; | |
| 1267 } | |
| 1268 } | |
| 1269 return false; | |
| 1270 } | |
| 1271 | |
| 791 } // namespace browser_sync | 1272 } // namespace browser_sync |
| OLD | NEW |