| Index: sync/internal_api/sync_encryption_handler_impl_unittest.cc
|
| diff --git a/sync/internal_api/sync_encryption_handler_impl_unittest.cc b/sync/internal_api/sync_encryption_handler_impl_unittest.cc
|
| index cc31a8e8f75f2a93ca4793049bfad6dbb51678a5..f237556f87f87b116149506810909ec2e06a4505 100644
|
| --- a/sync/internal_api/sync_encryption_handler_impl_unittest.cc
|
| +++ b/sync/internal_api/sync_encryption_handler_impl_unittest.cc
|
| @@ -12,6 +12,7 @@
|
| #include "sync/internal_api/public/base/model_type_test_util.h"
|
| #include "sync/internal_api/public/read_node.h"
|
| #include "sync/internal_api/public/read_transaction.h"
|
| +#include "sync/internal_api/public/write_node.h"
|
| #include "sync/internal_api/public/write_transaction.h"
|
| #include "sync/internal_api/public/test/test_user_share.h"
|
| #include "sync/protocol/nigori_specifics.pb.h"
|
| @@ -33,6 +34,8 @@ using ::testing::_;
|
| using ::testing::Mock;
|
| using ::testing::StrictMock;
|
|
|
| +static const char kKeystoreKey[] = "keystore_key";
|
| +
|
| class SyncEncryptionHandlerObserverMock
|
| : public SyncEncryptionHandler::Observer {
|
| public:
|
| @@ -46,7 +49,7 @@ class SyncEncryptionHandlerObserverMock
|
| void(ModelTypeSet, bool)); // NOLINT
|
| MOCK_METHOD0(OnEncryptionComplete, void()); // NOLINT
|
| MOCK_METHOD1(OnCryptographerStateChanged, void(Cryptographer*)); // NOLINT
|
| - MOCK_METHOD1(OnPassphraseStateChanged, void(PassphraseState)); // NOLINT
|
| + MOCK_METHOD1(OnPassphraseTypeChanged, void(PassphraseType)); // NOLINT
|
| };
|
|
|
| } // namespace
|
| @@ -63,6 +66,7 @@ class SyncEncryptionHandlerImplTest : public ::testing::Test {
|
| }
|
|
|
| virtual void TearDown() {
|
| + PumpLoop();
|
| test_user_share_.TearDown();
|
| }
|
|
|
| @@ -113,6 +117,54 @@ class SyncEncryptionHandlerImplTest : public ::testing::Test {
|
| return encryption_handler_->GetCryptographerUnsafe();
|
| }
|
|
|
| + void VerifyMigratedNigori(PassphraseType passphrase_type,
|
| + const std::string& passphrase) {
|
| + VerifyMigratedNigoriWithTimestamp(0, passphrase_type, passphrase);
|
| + }
|
| +
|
| + void VerifyMigratedNigoriWithTimestamp(
|
| + int64 migration_time,
|
| + PassphraseType passphrase_type,
|
| + const std::string& passphrase) {
|
| + ReadTransaction trans(FROM_HERE, user_share());
|
| + ReadNode nigori_node(&trans);
|
| + ASSERT_EQ(nigori_node.InitByTagLookup(kNigoriTag), BaseNode::INIT_OK);
|
| + const sync_pb::NigoriSpecifics& nigori = nigori_node.GetNigoriSpecifics();
|
| + if (migration_time > 0)
|
| + EXPECT_EQ(migration_time, nigori.keystore_migration_time());
|
| + else
|
| + EXPECT_TRUE(nigori.has_keystore_migration_time());
|
| + EXPECT_TRUE(nigori.keybag_is_frozen());
|
| + if (passphrase_type == CUSTOM_PASSPHRASE ||
|
| + passphrase_type == FROZEN_IMPLICIT_PASSPHRASE) {
|
| + EXPECT_TRUE(nigori.encrypt_everything());
|
| + EXPECT_TRUE(nigori.keystore_decryptor_token().blob().empty());
|
| + if (passphrase_type == CUSTOM_PASSPHRASE) {
|
| + EXPECT_EQ(sync_pb::NigoriSpecifics::CUSTOM_PASSPHRASE,
|
| + nigori.passphrase_type());
|
| + } else {
|
| + EXPECT_EQ(sync_pb::NigoriSpecifics::FROZEN_IMPLICIT_PASSPHRASE,
|
| + nigori.passphrase_type());
|
| + }
|
| + } else {
|
| + EXPECT_FALSE(nigori.encrypt_everything());
|
| + EXPECT_FALSE(nigori.keystore_decryptor_token().blob().empty());
|
| + EXPECT_EQ(sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE,
|
| + nigori.passphrase_type());
|
| + Cryptographer keystore_cryptographer(&encryptor_);
|
| + KeyParams params = {"localhost", "dummy", kKeystoreKey};
|
| + keystore_cryptographer.AddKey(params);
|
| + EXPECT_TRUE(keystore_cryptographer.CanDecryptUsingDefaultKey(
|
| + nigori.keystore_decryptor_token()));
|
| + }
|
| +
|
| + Cryptographer temp_cryptographer(&encryptor_);
|
| + KeyParams params = {"localhost", "dummy", passphrase};
|
| + temp_cryptographer.AddKey(params);
|
| + EXPECT_TRUE(temp_cryptographer.CanDecryptUsingDefaultKey(
|
| + nigori.encryption_keybag()));
|
| + }
|
| +
|
| protected:
|
| TestUserShare test_user_share_;
|
| FakeEncryptor encryptor_;
|
| @@ -324,7 +376,7 @@ TEST_F(SyncEncryptionHandlerImplTest, ReceiveOldNigori) {
|
| our_encrypted_specifics,
|
| our_encrypted_specifics.mutable_encrypted());
|
| GetCryptographer()->GetKeys(
|
| - current_nigori_specifics.mutable_encrypted());
|
| + current_nigori_specifics.mutable_encryption_keybag());
|
| current_nigori_specifics.set_encrypt_everything(true);
|
|
|
| EXPECT_CALL(*observer(), OnCryptographerStateChanged(_));
|
| @@ -342,7 +394,7 @@ TEST_F(SyncEncryptionHandlerImplTest, ReceiveOldNigori) {
|
| // Now set up the old nigori specifics and apply it on top.
|
| // Has an old set of keys, and no encrypted types.
|
| sync_pb::NigoriSpecifics old_nigori;
|
| - other_cryptographer.GetKeys(old_nigori.mutable_encrypted());
|
| + other_cryptographer.GetKeys(old_nigori.mutable_encryption_keybag());
|
|
|
| EXPECT_CALL(*observer(), OnCryptographerStateChanged(_));
|
| {
|
| @@ -366,17 +418,17 @@ TEST_F(SyncEncryptionHandlerImplTest, ReceiveOldNigori) {
|
| // In addition, the nigori node should match the current encryption state.
|
| ReadTransaction trans(FROM_HERE, user_share());
|
| ReadNode nigori_node(&trans);
|
| - ASSERT_EQ(nigori_node.InitByTagLookup(ModelTypeToRootTag(NIGORI)),
|
| - BaseNode::INIT_OK);
|
| + ASSERT_EQ(nigori_node.InitByTagLookup(kNigoriTag), BaseNode::INIT_OK);
|
| const sync_pb::NigoriSpecifics& nigori = nigori_node.GetNigoriSpecifics();
|
| EXPECT_TRUE(GetCryptographer()->CanDecryptUsingDefaultKey(
|
| our_encrypted_specifics.encrypted()));
|
| EXPECT_TRUE(GetCryptographer()->CanDecrypt(
|
| other_encrypted_specifics.encrypted()));
|
| - EXPECT_TRUE(GetCryptographer()->CanDecrypt(nigori.encrypted()));
|
| + EXPECT_TRUE(GetCryptographer()->CanDecrypt(nigori.encryption_keybag()));
|
| EXPECT_TRUE(nigori.encrypt_everything());
|
| EXPECT_TRUE(
|
| - GetCryptographer()->CanDecryptUsingDefaultKey(nigori.encrypted()));
|
| + GetCryptographer()->CanDecryptUsingDefaultKey(
|
| + nigori.encryption_keybag()));
|
| }
|
| EXPECT_TRUE(encryption_handler()->EncryptEverythingEnabled());
|
| }
|
| @@ -393,13 +445,1162 @@ TEST_F(SyncEncryptionHandlerImplTest, SetKeystoreUpdatedBoostrapToken) {
|
| EXPECT_TRUE(encryption_handler()->NeedKeystoreKey(trans.GetWrappedTrans()));
|
| Mock::VerifyAndClearExpectations(observer());
|
|
|
| - const char kValidKey[] = "keystore_key";
|
| EXPECT_CALL(*observer(),
|
| - OnBootstrapTokenUpdated(kValidKey, KEYSTORE_BOOTSTRAP_TOKEN));
|
| - EXPECT_TRUE(encryption_handler()->SetKeystoreKey(kValidKey,
|
| + OnBootstrapTokenUpdated(kKeystoreKey, KEYSTORE_BOOTSTRAP_TOKEN));
|
| + EXPECT_TRUE(encryption_handler()->SetKeystoreKey(kKeystoreKey,
|
| trans.GetWrappedTrans()));
|
| EXPECT_FALSE(encryption_handler()->NeedKeystoreKey(trans.GetWrappedTrans()));
|
| EXPECT_FALSE(GetCryptographer()->is_initialized());
|
| }
|
|
|
| +// Ensure GetKeystoreDecryptor only updates the keystore decryptor token if it
|
| +// wasn't already set properly. Otherwise, the decryptor should remain the
|
| +// same.
|
| +TEST_F(SyncEncryptionHandlerImplTest, GetKeystoreDecryptor) {
|
| + const char kCurKey[] = "cur";
|
| + sync_pb::EncryptedData encrypted;
|
| + Cryptographer other_cryptographer(GetCryptographer()->encryptor());
|
| + KeyParams cur_key = {"localhost", "dummy", kCurKey};
|
| + other_cryptographer.AddKey(cur_key);
|
| + EXPECT_TRUE(other_cryptographer.is_ready());
|
| + EXPECT_TRUE(encryption_handler()->GetKeystoreDecryptor(
|
| + other_cryptographer,
|
| + kKeystoreKey,
|
| + &encrypted));
|
| + std::string serialized = encrypted.SerializeAsString();
|
| + EXPECT_TRUE(encryption_handler()->GetKeystoreDecryptor(
|
| + other_cryptographer,
|
| + kKeystoreKey,
|
| + &encrypted));
|
| + EXPECT_EQ(serialized, encrypted.SerializeAsString());
|
| +}
|
| +
|
| +// Test that we don't attempt to migrate while an implicit passphrase is pending
|
| +// and that once we do decrypt pending keys we migrate the nigori. Once
|
| +// migrated, we should be in keystore passphrase state.
|
| +TEST_F(SyncEncryptionHandlerImplTest, MigrateOnDecryptImplicitPass) {
|
| + const char kOtherKey[] = "other";
|
| + {
|
| + EXPECT_CALL(*observer(),
|
| + OnBootstrapTokenUpdated(_, KEYSTORE_BOOTSTRAP_TOKEN));
|
| + ReadTransaction trans(FROM_HERE, user_share());
|
| + encryption_handler()->SetKeystoreKey(kKeystoreKey, trans.GetWrappedTrans());
|
| + Mock::VerifyAndClearExpectations(observer());
|
| + }
|
| + EXPECT_FALSE(encryption_handler()->MigratedToKeystore());
|
| +
|
| + {
|
| + WriteTransaction trans(FROM_HERE, user_share());
|
| + WriteNode nigori_node(&trans);
|
| + ASSERT_EQ(nigori_node.InitByTagLookup(kNigoriTag), BaseNode::INIT_OK);
|
| + Cryptographer other_cryptographer(GetCryptographer()->encryptor());
|
| + KeyParams other_key = {"localhost", "dummy", kOtherKey};
|
| + other_cryptographer.AddKey(other_key);
|
| +
|
| + sync_pb::NigoriSpecifics nigori;
|
| + other_cryptographer.GetKeys(nigori.mutable_encryption_keybag());
|
| + nigori.set_keybag_is_frozen(false);
|
| + nigori.set_encrypt_everything(false);
|
| + EXPECT_CALL(*observer(),
|
| + OnCryptographerStateChanged(_));
|
| + EXPECT_CALL(*observer(),
|
| + OnPassphraseRequired(_, _));
|
| + encryption_handler()->ApplyNigoriUpdate(nigori, trans.GetWrappedTrans());
|
| + nigori_node.SetNigoriSpecifics(nigori);
|
| + }
|
| + // Run any tasks posted via AppplyNigoriUpdate.
|
| + PumpLoop();
|
| + EXPECT_FALSE(encryption_handler()->MigratedToKeystore());
|
| + Mock::VerifyAndClearExpectations(observer());
|
| +
|
| + EXPECT_CALL(*observer(),
|
| + OnCryptographerStateChanged(_));
|
| + EXPECT_CALL(*observer(),
|
| + OnPassphraseAccepted());
|
| + EXPECT_CALL(*observer(),
|
| + OnPassphraseTypeChanged(KEYSTORE_PASSPHRASE));
|
| + EXPECT_CALL(*observer(),
|
| + OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN));
|
| + EXPECT_CALL(*observer(),
|
| + OnEncryptionComplete());
|
| + EXPECT_FALSE(encryption_handler()->MigratedToKeystore());
|
| + encryption_handler()->SetDecryptionPassphrase(kOtherKey);
|
| + EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
|
| + EXPECT_EQ(KEYSTORE_PASSPHRASE, encryption_handler()->GetPassphraseType());
|
| + VerifyMigratedNigori(KEYSTORE_PASSPHRASE, kOtherKey);
|
| +}
|
| +
|
| +// Test that we don't attempt to migrate while a custom passphrase is pending,
|
| +// and that once we do decrypt pending keys we migrate the nigori. Once
|
| +// migrated, we should be in custom passphrase state with encrypt everything.
|
| +TEST_F(SyncEncryptionHandlerImplTest, MigrateOnDecryptCustomPass) {
|
| + const char kOtherKey[] = "other";
|
| + {
|
| + EXPECT_CALL(*observer(),
|
| + OnBootstrapTokenUpdated(_, KEYSTORE_BOOTSTRAP_TOKEN));
|
| + ReadTransaction trans(FROM_HERE, user_share());
|
| + encryption_handler()->SetKeystoreKey(kKeystoreKey, trans.GetWrappedTrans());
|
| + Mock::VerifyAndClearExpectations(observer());
|
| + }
|
| + EXPECT_FALSE(encryption_handler()->MigratedToKeystore());
|
| +
|
| + {
|
| + WriteTransaction trans(FROM_HERE, user_share());
|
| + WriteNode nigori_node(&trans);
|
| + ASSERT_EQ(nigori_node.InitByTagLookup(kNigoriTag), BaseNode::INIT_OK);
|
| + Cryptographer other_cryptographer(GetCryptographer()->encryptor());
|
| + KeyParams other_key = {"localhost", "dummy", kOtherKey};
|
| + other_cryptographer.AddKey(other_key);
|
| +
|
| + sync_pb::NigoriSpecifics nigori;
|
| + other_cryptographer.GetKeys(nigori.mutable_encryption_keybag());
|
| + nigori.set_keybag_is_frozen(true);
|
| + nigori.set_encrypt_everything(false);
|
| + EXPECT_CALL(*observer(),
|
| + OnCryptographerStateChanged(_));
|
| + EXPECT_CALL(*observer(),
|
| + OnPassphraseRequired(_, _));
|
| + EXPECT_CALL(*observer(),
|
| + OnPassphraseTypeChanged(CUSTOM_PASSPHRASE));
|
| + encryption_handler()->ApplyNigoriUpdate(nigori, trans.GetWrappedTrans());
|
| + nigori_node.SetNigoriSpecifics(nigori);
|
| + }
|
| + // Run any tasks posted via AppplyNigoriUpdate.
|
| + PumpLoop();
|
| + EXPECT_FALSE(encryption_handler()->MigratedToKeystore());
|
| + Mock::VerifyAndClearExpectations(observer());
|
| +
|
| + EXPECT_CALL(*observer(),
|
| + OnCryptographerStateChanged(_));
|
| + EXPECT_CALL(*observer(),
|
| + OnPassphraseAccepted());
|
| + EXPECT_CALL(*observer(),
|
| + OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN));
|
| + EXPECT_CALL(*observer(),
|
| + OnEncryptedTypesChanged(_, true));
|
| + EXPECT_CALL(*observer(),
|
| + OnEncryptionComplete()).Times(2);
|
| + EXPECT_FALSE(encryption_handler()->MigratedToKeystore());
|
| + encryption_handler()->SetDecryptionPassphrase(kOtherKey);
|
| + EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
|
| + EXPECT_EQ(CUSTOM_PASSPHRASE, encryption_handler()->GetPassphraseType());
|
| + VerifyMigratedNigori(CUSTOM_PASSPHRASE, kOtherKey);
|
| +}
|
| +
|
| +// Test that we trigger a migration when we set the keystore key, had an
|
| +// implicit passphrase, and did not have encrypt everything. We should switch
|
| +// to KEYSTORE_PASSPHRASE.
|
| +TEST_F(SyncEncryptionHandlerImplTest, MigrateOnKeystoreKeyAvailableImplicit) {
|
| + const char kCurKey[] = "cur";
|
| + KeyParams current_key = {"localhost", "dummy", kCurKey};
|
| + GetCryptographer()->AddKey(current_key);
|
| + EXPECT_CALL(*observer(),
|
| + OnCryptographerStateChanged(_));
|
| + EXPECT_CALL(*observer(),
|
| + OnEncryptedTypesChanged(_, false));
|
| + EXPECT_CALL(*observer(),
|
| + OnEncryptionComplete());
|
| + encryption_handler()->Init();
|
| + Mock::VerifyAndClearExpectations(observer());
|
| +
|
| + {
|
| + ReadTransaction trans(FROM_HERE, user_share());
|
| + // Once we provide a keystore key, we should perform the migration.
|
| + EXPECT_CALL(*observer(),
|
| + OnBootstrapTokenUpdated(_, KEYSTORE_BOOTSTRAP_TOKEN));
|
| + encryption_handler()->SetKeystoreKey(kKeystoreKey, trans.GetWrappedTrans());
|
| + }
|
| + EXPECT_CALL(*observer(),
|
| + OnPassphraseTypeChanged(KEYSTORE_PASSPHRASE));
|
| + // The actual migration gets posted, so run all pending tasks.
|
| + PumpLoop();
|
| + EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
|
| + EXPECT_EQ(KEYSTORE_PASSPHRASE,
|
| + encryption_handler()->GetPassphraseType());
|
| + EXPECT_FALSE(encryption_handler()->EncryptEverythingEnabled());
|
| + VerifyMigratedNigori(KEYSTORE_PASSPHRASE, kCurKey);
|
| +}
|
| +
|
| +// Test that we trigger a migration when we set the keystore key, had an
|
| +// implicit passphrase, and encrypt everything enabled. We should switch to
|
| +// FROZEN_IMPLICIT_PASSPHRASE.
|
| +TEST_F(SyncEncryptionHandlerImplTest,
|
| + MigrateOnKeystoreKeyAvailableFrozenImplicit) {
|
| + const char kCurKey[] = "cur";
|
| + KeyParams current_key = {"localhost", "dummy", kCurKey};
|
| + GetCryptographer()->AddKey(current_key);
|
| + EXPECT_CALL(*observer(),
|
| + OnCryptographerStateChanged(_));
|
| + EXPECT_CALL(*observer(),
|
| + OnEncryptedTypesChanged(_, false));
|
| + EXPECT_CALL(*observer(),
|
| + OnEncryptionComplete());
|
| + encryption_handler()->Init();
|
| + Mock::VerifyAndClearExpectations(observer());
|
| +
|
| + EXPECT_CALL(*observer(),
|
| + OnEncryptedTypesChanged(_, true));
|
| + EXPECT_CALL(*observer(),
|
| + OnEncryptionComplete());
|
| + encryption_handler()->EnableEncryptEverything();
|
| +
|
| + {
|
| + ReadTransaction trans(FROM_HERE, user_share());
|
| + // Once we provide a keystore key, we should perform the migration.
|
| + EXPECT_CALL(*observer(),
|
| + OnBootstrapTokenUpdated(_, KEYSTORE_BOOTSTRAP_TOKEN));
|
| + encryption_handler()->SetKeystoreKey(kKeystoreKey, trans.GetWrappedTrans());
|
| + }
|
| + EXPECT_CALL(*observer(),
|
| + OnPassphraseTypeChanged(FROZEN_IMPLICIT_PASSPHRASE));
|
| + // The actual migration gets posted, so run all pending tasks.
|
| + PumpLoop();
|
| + EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
|
| + EXPECT_EQ(FROZEN_IMPLICIT_PASSPHRASE,
|
| + encryption_handler()->GetPassphraseType());
|
| + EXPECT_TRUE(encryption_handler()->EncryptEverythingEnabled());
|
| + VerifyMigratedNigori(FROZEN_IMPLICIT_PASSPHRASE, kCurKey);
|
| +}
|
| +
|
| +// Test that we trigger a migration when we set the keystore key, had a
|
| +// custom passphrase, and encrypt everything enabled. The passphrase state
|
| +// should remain as CUSTOM_PASSPHRASE, and encrypt everything stay the same.
|
| +TEST_F(SyncEncryptionHandlerImplTest,
|
| + MigrateOnKeystoreKeyAvailableCustomWithEncryption) {
|
| + const char kCurKey[] = "cur";
|
| + EXPECT_CALL(*observer(),
|
| + OnCryptographerStateChanged(_)).Times(2);
|
| + EXPECT_CALL(*observer(),
|
| + OnPassphraseRequired(_, _));
|
| + EXPECT_CALL(*observer(),
|
| + OnPassphraseAccepted());
|
| + EXPECT_CALL(*observer(),
|
| + OnEncryptedTypesChanged(_, false));
|
| + EXPECT_CALL(*observer(),
|
| + OnEncryptionComplete());
|
| + EXPECT_CALL(*observer(),
|
| + OnPassphraseTypeChanged(CUSTOM_PASSPHRASE));
|
| + EXPECT_CALL(*observer(),
|
| + OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN));
|
| + encryption_handler()->Init();
|
| + encryption_handler()->SetEncryptionPassphrase(kCurKey, true);
|
| + Mock::VerifyAndClearExpectations(observer());
|
| +
|
| + EXPECT_CALL(*observer(),
|
| + OnEncryptedTypesChanged(_, true));
|
| + EXPECT_CALL(*observer(),
|
| + OnEncryptionComplete());
|
| + encryption_handler()->EnableEncryptEverything();
|
| + Mock::VerifyAndClearExpectations(observer());
|
| +
|
| + {
|
| + ReadTransaction trans(FROM_HERE, user_share());
|
| + // Once we provide a keystore key, we should perform the migration.
|
| + EXPECT_CALL(*observer(),
|
| + OnBootstrapTokenUpdated(_, KEYSTORE_BOOTSTRAP_TOKEN));
|
| + encryption_handler()->SetKeystoreKey(kKeystoreKey, trans.GetWrappedTrans());
|
| + }
|
| + // The actual migration gets posted, so run all pending tasks.
|
| + PumpLoop();
|
| + EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
|
| + EXPECT_EQ(CUSTOM_PASSPHRASE,
|
| + encryption_handler()->GetPassphraseType());
|
| + EXPECT_TRUE(encryption_handler()->EncryptEverythingEnabled());
|
| + VerifyMigratedNigori(CUSTOM_PASSPHRASE, kCurKey);
|
| +}
|
| +
|
| +// Test that we trigger a migration when we set the keystore key, had a
|
| +// custom passphrase, and did not have encrypt everything. The passphrase state
|
| +// should remain as CUSTOM_PASSPHRASE, and encrypt everything should be enabled.
|
| +TEST_F(SyncEncryptionHandlerImplTest,
|
| + MigrateOnKeystoreKeyAvailableCustomNoEncryption) {
|
| + const char kCurKey[] = "cur";
|
| + EXPECT_CALL(*observer(),
|
| + OnCryptographerStateChanged(_)).Times(2);
|
| + EXPECT_CALL(*observer(),
|
| + OnPassphraseRequired(_, _));
|
| + EXPECT_CALL(*observer(),
|
| + OnPassphraseAccepted());
|
| + EXPECT_CALL(*observer(),
|
| + OnEncryptedTypesChanged(_, false));
|
| + EXPECT_CALL(*observer(),
|
| + OnEncryptionComplete());
|
| + EXPECT_CALL(*observer(),
|
| + OnPassphraseTypeChanged(CUSTOM_PASSPHRASE));
|
| + EXPECT_CALL(*observer(),
|
| + OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN));
|
| + encryption_handler()->Init();
|
| + encryption_handler()->SetEncryptionPassphrase(kCurKey, true);
|
| + Mock::VerifyAndClearExpectations(observer());
|
| +
|
| + {
|
| + ReadTransaction trans(FROM_HERE, user_share());
|
| + // Once we provide a keystore key, we should perform the migration.
|
| + EXPECT_CALL(*observer(),
|
| + OnBootstrapTokenUpdated(_, KEYSTORE_BOOTSTRAP_TOKEN));
|
| + encryption_handler()->SetKeystoreKey(kKeystoreKey, trans.GetWrappedTrans());
|
| + }
|
| + EXPECT_CALL(*observer(),
|
| + OnEncryptedTypesChanged(_, true));
|
| + EXPECT_CALL(*observer(),
|
| + OnEncryptionComplete());
|
| + // The actual migration gets posted, so run all pending tasks.
|
| + PumpLoop();
|
| + EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
|
| + EXPECT_EQ(CUSTOM_PASSPHRASE,
|
| + encryption_handler()->GetPassphraseType());
|
| + EXPECT_TRUE(encryption_handler()->EncryptEverythingEnabled());
|
| + VerifyMigratedNigori(CUSTOM_PASSPHRASE, kCurKey);
|
| +}
|
| +
|
| +// Test that we can handle receiving a migrated nigori node in the
|
| +// KEYSTORE_PASS state, and use the keystore decryptor token to decrypt the
|
| +// keybag.
|
| +TEST_F(SyncEncryptionHandlerImplTest, ReceiveMigratedNigoriKeystorePass) {
|
| + const char kCurKey[] = "cur";
|
| + sync_pb::EncryptedData keystore_decryptor_token;
|
| + Cryptographer other_cryptographer(GetCryptographer()->encryptor());
|
| + KeyParams cur_key = {"localhost", "dummy", kCurKey};
|
| + other_cryptographer.AddKey(cur_key);
|
| + EXPECT_TRUE(other_cryptographer.is_ready());
|
| + EXPECT_TRUE(encryption_handler()->GetKeystoreDecryptor(
|
| + other_cryptographer,
|
| + kKeystoreKey,
|
| + &keystore_decryptor_token));
|
| + EXPECT_FALSE(encryption_handler()->MigratedToKeystore());
|
| + EXPECT_FALSE(GetCryptographer()->is_ready());
|
| + EXPECT_NE(encryption_handler()->GetPassphraseType(), KEYSTORE_PASSPHRASE);
|
| +
|
| + // Now build a nigori node with the generated keystore decryptor token and
|
| + // initialize the encryption handler with it. The cryptographer should be
|
| + // initialized properly to decrypt both kCurKey and kKeystoreKey.
|
| + {
|
| + WriteTransaction trans(FROM_HERE, user_share());
|
| + WriteNode nigori_node(&trans);
|
| + ASSERT_EQ(nigori_node.InitByTagLookup(kNigoriTag), BaseNode::INIT_OK);
|
| + sync_pb::NigoriSpecifics nigori;
|
| + nigori.mutable_keystore_decryptor_token()->CopyFrom(
|
| + keystore_decryptor_token);
|
| + other_cryptographer.GetKeys(nigori.mutable_encryption_keybag());
|
| + nigori.set_keybag_is_frozen(true);
|
| + nigori.set_keystore_migration_time(1);
|
| + nigori.set_passphrase_type(sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE);
|
| +
|
| + EXPECT_CALL(*observer(),
|
| + OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN));
|
| + EXPECT_CALL(*observer(),
|
| + OnBootstrapTokenUpdated(_, KEYSTORE_BOOTSTRAP_TOKEN));
|
| + EXPECT_CALL(*observer(),
|
| + OnPassphraseTypeChanged(KEYSTORE_PASSPHRASE));
|
| + EXPECT_CALL(*observer(),
|
| + OnCryptographerStateChanged(_)).Times(2);
|
| + encryption_handler()->SetKeystoreKey(kKeystoreKey, trans.GetWrappedTrans());
|
| + encryption_handler()->ApplyNigoriUpdate(nigori, trans.GetWrappedTrans());
|
| + nigori_node.SetNigoriSpecifics(nigori);
|
| + }
|
| + // Run any tasks posted via AppplyNigoriUpdate.
|
| + PumpLoop();
|
| + Mock::VerifyAndClearExpectations(observer());
|
| +
|
| + EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
|
| + EXPECT_TRUE(GetCryptographer()->is_ready());
|
| + EXPECT_EQ(encryption_handler()->GetPassphraseType(), KEYSTORE_PASSPHRASE);
|
| + EXPECT_FALSE(encryption_handler()->EncryptEverythingEnabled());
|
| + VerifyMigratedNigoriWithTimestamp(1, KEYSTORE_PASSPHRASE, kCurKey);
|
| +
|
| + // Check that the cryptographer still encrypts with the current key.
|
| + sync_pb::EncryptedData current_encrypted;
|
| + other_cryptographer.EncryptString("string", ¤t_encrypted);
|
| + EXPECT_TRUE(GetCryptographer()->CanDecryptUsingDefaultKey(current_encrypted));
|
| +
|
| + // Check that the cryptographer can decrypt keystore key based encryption.
|
| + Cryptographer keystore_cryptographer(GetCryptographer()->encryptor());
|
| + KeyParams keystore_key = {"localhost", "dummy", kKeystoreKey};
|
| + keystore_cryptographer.AddKey(keystore_key);
|
| + sync_pb::EncryptedData keystore_encrypted;
|
| + keystore_cryptographer.EncryptString("string", &keystore_encrypted);
|
| + EXPECT_TRUE(GetCryptographer()->CanDecrypt(keystore_encrypted));
|
| +}
|
| +
|
| +// Test that we handle receiving migrated nigori's with
|
| +// FROZEN_IMPLICIT_PASSPHRASE state. We should be in a pending key state until
|
| +// we supply the pending frozen implicit passphrase key.
|
| +TEST_F(SyncEncryptionHandlerImplTest, ReceiveMigratedNigoriFrozenImplicitPass) {
|
| + const char kCurKey[] = "cur";
|
| + sync_pb::EncryptedData encrypted;
|
| + Cryptographer other_cryptographer(GetCryptographer()->encryptor());
|
| + KeyParams cur_key = {"localhost", "dummy", kCurKey};
|
| + other_cryptographer.AddKey(cur_key);
|
| + EXPECT_FALSE(encryption_handler()->MigratedToKeystore());
|
| +
|
| + {
|
| + EXPECT_CALL(*observer(),
|
| + OnBootstrapTokenUpdated(_, KEYSTORE_BOOTSTRAP_TOKEN));
|
| + ReadTransaction trans(FROM_HERE, user_share());
|
| + encryption_handler()->SetKeystoreKey(kKeystoreKey, trans.GetWrappedTrans());
|
| + }
|
| + EXPECT_FALSE(encryption_handler()->MigratedToKeystore());
|
| +
|
| + {
|
| + EXPECT_CALL(*observer(),
|
| + OnPassphraseTypeChanged(FROZEN_IMPLICIT_PASSPHRASE));
|
| + EXPECT_CALL(*observer(),
|
| + OnPassphraseRequired(_, _));
|
| + EXPECT_CALL(*observer(),
|
| + OnCryptographerStateChanged(_));
|
| + EXPECT_CALL(*observer(),
|
| + OnEncryptedTypesChanged(_, true));
|
| + WriteTransaction trans(FROM_HERE, user_share());
|
| + WriteNode nigori_node(&trans);
|
| + ASSERT_EQ(nigori_node.InitByTagLookup(kNigoriTag), BaseNode::INIT_OK);
|
| + sync_pb::NigoriSpecifics nigori;
|
| + nigori.set_keybag_is_frozen(true);
|
| + nigori.set_passphrase_type(
|
| + sync_pb::NigoriSpecifics::FROZEN_IMPLICIT_PASSPHRASE);
|
| + nigori.set_keystore_migration_time(1);
|
| + nigori.set_encrypt_everything(true);
|
| + other_cryptographer.GetKeys(nigori.mutable_encryption_keybag());
|
| + encryption_handler()->ApplyNigoriUpdate(nigori, trans.GetWrappedTrans());
|
| + nigori_node.SetNigoriSpecifics(nigori);
|
| + }
|
| + // Run any tasks posted via AppplyNigoriUpdate.
|
| + PumpLoop();
|
| + Mock::VerifyAndClearExpectations(observer());
|
| +
|
| + EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
|
| + EXPECT_EQ(FROZEN_IMPLICIT_PASSPHRASE,
|
| + encryption_handler()->GetPassphraseType());
|
| + EXPECT_TRUE(GetCryptographer()->has_pending_keys());
|
| + EXPECT_TRUE(encryption_handler()->EncryptEverythingEnabled());
|
| +
|
| + EXPECT_CALL(*observer(),
|
| + OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN));
|
| + EXPECT_CALL(*observer(),
|
| + OnCryptographerStateChanged(_));
|
| + EXPECT_CALL(*observer(),
|
| + OnEncryptionComplete());
|
| + EXPECT_CALL(*observer(),
|
| + OnPassphraseAccepted());
|
| + encryption_handler()->SetDecryptionPassphrase(kCurKey);
|
| + EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
|
| + EXPECT_TRUE(GetCryptographer()->is_ready());
|
| + VerifyMigratedNigoriWithTimestamp(1, FROZEN_IMPLICIT_PASSPHRASE, kCurKey);
|
| +
|
| + // Check that the cryptographer still encrypts with the current key.
|
| + sync_pb::EncryptedData current_encrypted;
|
| + other_cryptographer.EncryptString("string", ¤t_encrypted);
|
| + EXPECT_TRUE(GetCryptographer()->CanDecryptUsingDefaultKey(current_encrypted));
|
| +
|
| + // Check that the cryptographer can decrypt keystore key based encryption.
|
| + Cryptographer keystore_cryptographer(GetCryptographer()->encryptor());
|
| + KeyParams keystore_key = {"localhost", "dummy", kKeystoreKey};
|
| + keystore_cryptographer.AddKey(keystore_key);
|
| + sync_pb::EncryptedData keystore_encrypted;
|
| + keystore_cryptographer.EncryptString("string", &keystore_encrypted);
|
| + EXPECT_TRUE(GetCryptographer()->CanDecrypt(keystore_encrypted));
|
| +}
|
| +
|
| +// Test that we handle receiving migrated nigori's with
|
| +// CUSTOM_PASSPHRASE state. We should be in a pending key state until we
|
| +// provide the custom passphrase key.
|
| +TEST_F(SyncEncryptionHandlerImplTest, ReceiveMigratedNigoriCustomPass) {
|
| + const char kKeystoreKey[] = "keystore_key";
|
| + const char kCurKey[] = "cur";
|
| + sync_pb::EncryptedData encrypted;
|
| + Cryptographer other_cryptographer(GetCryptographer()->encryptor());
|
| + KeyParams cur_key = {"localhost", "dummy", kCurKey};
|
| + other_cryptographer.AddKey(cur_key);
|
| + EXPECT_FALSE(encryption_handler()->MigratedToKeystore());
|
| +
|
| + {
|
| + EXPECT_CALL(*observer(),
|
| + OnBootstrapTokenUpdated(_, KEYSTORE_BOOTSTRAP_TOKEN));
|
| + ReadTransaction trans(FROM_HERE, user_share());
|
| + encryption_handler()->SetKeystoreKey(kKeystoreKey,
|
| + trans.GetWrappedTrans());
|
| + }
|
| + EXPECT_FALSE(encryption_handler()->MigratedToKeystore());
|
| +
|
| + {
|
| + EXPECT_CALL(*observer(),
|
| + OnPassphraseTypeChanged(CUSTOM_PASSPHRASE));
|
| + EXPECT_CALL(*observer(),
|
| + OnPassphraseRequired(_, _));
|
| + EXPECT_CALL(*observer(),
|
| + OnCryptographerStateChanged(_));
|
| + EXPECT_CALL(*observer(),
|
| + OnEncryptedTypesChanged(_, true));
|
| + WriteTransaction trans(FROM_HERE, user_share());
|
| + WriteNode nigori_node(&trans);
|
| + ASSERT_EQ(nigori_node.InitByTagLookup(kNigoriTag), BaseNode::INIT_OK);
|
| + sync_pb::NigoriSpecifics nigori;
|
| + nigori.set_keybag_is_frozen(true);
|
| + nigori.set_passphrase_type(sync_pb::NigoriSpecifics::CUSTOM_PASSPHRASE);
|
| + nigori.set_keystore_migration_time(1);
|
| + nigori.set_encrypt_everything(true);
|
| + other_cryptographer.GetKeys(nigori.mutable_encryption_keybag());
|
| + encryption_handler()->ApplyNigoriUpdate(nigori, trans.GetWrappedTrans());
|
| + nigori_node.SetNigoriSpecifics(nigori);
|
| + }
|
| + // Run any tasks posted via AppplyNigoriUpdate.
|
| + PumpLoop();
|
| + Mock::VerifyAndClearExpectations(observer());
|
| +
|
| + EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
|
| + EXPECT_EQ(CUSTOM_PASSPHRASE, encryption_handler()->GetPassphraseType());
|
| + EXPECT_TRUE(GetCryptographer()->has_pending_keys());
|
| + EXPECT_TRUE(encryption_handler()->EncryptEverythingEnabled());
|
| +
|
| + EXPECT_CALL(*observer(),
|
| + OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN));
|
| + EXPECT_CALL(*observer(),
|
| + OnCryptographerStateChanged(_));
|
| + EXPECT_CALL(*observer(),
|
| + OnEncryptionComplete());
|
| + EXPECT_CALL(*observer(),
|
| + OnPassphraseAccepted());
|
| + encryption_handler()->SetDecryptionPassphrase(kCurKey);
|
| + EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
|
| + EXPECT_TRUE(GetCryptographer()->is_ready());
|
| + VerifyMigratedNigoriWithTimestamp(1, CUSTOM_PASSPHRASE, kCurKey);
|
| +
|
| + // Check that the cryptographer still encrypts with the current key.
|
| + sync_pb::EncryptedData current_encrypted;
|
| + other_cryptographer.EncryptString("string", ¤t_encrypted);
|
| + EXPECT_TRUE(GetCryptographer()->CanDecryptUsingDefaultKey(current_encrypted));
|
| +
|
| + // Check that the cryptographer can decrypt keystore key based encryption.
|
| + Cryptographer keystore_cryptographer(GetCryptographer()->encryptor());
|
| + KeyParams keystore_key = {"localhost", "dummy", kKeystoreKey};
|
| + keystore_cryptographer.AddKey(keystore_key);
|
| + sync_pb::EncryptedData keystore_encrypted;
|
| + keystore_cryptographer.EncryptString("string", &keystore_encrypted);
|
| + EXPECT_TRUE(GetCryptographer()->CanDecrypt(keystore_encrypted));
|
| +}
|
| +
|
| +// Test that if we have a migrated nigori with a custom passphrase, then receive
|
| +// and old implicit passphrase nigori, we properly overwrite it with the current
|
| +// state.
|
| +TEST_F(SyncEncryptionHandlerImplTest, ReceiveUnmigratedNigoriAfterMigration) {
|
| + const char kOldKey[] = "old";
|
| + const char kCurKey[] = "cur";
|
| + sync_pb::EncryptedData encrypted;
|
| + KeyParams old_key = {"localhost", "dummy", kOldKey};
|
| + KeyParams cur_key = {"localhost", "dummy", kCurKey};
|
| + GetCryptographer()->AddKey(old_key);
|
| + GetCryptographer()->AddKey(cur_key);
|
| +
|
| + // Build a migrated nigori with full encryption.
|
| + {
|
| + WriteTransaction trans(FROM_HERE, user_share());
|
| + WriteNode nigori_node(&trans);
|
| + ASSERT_EQ(nigori_node.InitByTagLookup(kNigoriTag), BaseNode::INIT_OK);
|
| + sync_pb::NigoriSpecifics nigori;
|
| + GetCryptographer()->GetKeys(nigori.mutable_encryption_keybag());
|
| + nigori.set_keybag_is_frozen(true);
|
| + nigori.set_keystore_migration_time(1);
|
| + nigori.set_passphrase_type(sync_pb::NigoriSpecifics::CUSTOM_PASSPHRASE);
|
| + nigori.set_encrypt_everything(true);
|
| + nigori_node.SetNigoriSpecifics(nigori);
|
| + }
|
| +
|
| + EXPECT_CALL(*observer(),
|
| + OnPassphraseTypeChanged(CUSTOM_PASSPHRASE));
|
| + EXPECT_CALL(*observer(),
|
| + OnCryptographerStateChanged(_));
|
| + EXPECT_CALL(*observer(),
|
| + OnEncryptedTypesChanged(_, true)).Times(2);
|
| + EXPECT_CALL(*observer(),
|
| + OnEncryptionComplete());
|
| + encryption_handler()->Init();
|
| + EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
|
| + EXPECT_TRUE(GetCryptographer()->is_ready());
|
| + EXPECT_EQ(encryption_handler()->GetPassphraseType(), CUSTOM_PASSPHRASE);
|
| + EXPECT_TRUE(encryption_handler()->EncryptEverythingEnabled());
|
| + VerifyMigratedNigoriWithTimestamp(1, CUSTOM_PASSPHRASE, kCurKey);
|
| +
|
| + {
|
| + EXPECT_CALL(*observer(),
|
| + OnBootstrapTokenUpdated(_, KEYSTORE_BOOTSTRAP_TOKEN));
|
| + ReadTransaction trans(FROM_HERE, user_share());
|
| + encryption_handler()->SetKeystoreKey(kKeystoreKey, trans.GetWrappedTrans());
|
| + }
|
| + Mock::VerifyAndClearExpectations(observer());
|
| +
|
| + // Now build an old unmigrated nigori node with old encrypted types. We should
|
| + // properly overwrite it with the migrated + encrypt everything state.
|
| + EXPECT_CALL(*observer(),
|
| + OnCryptographerStateChanged(_));
|
| + {
|
| + Cryptographer other_cryptographer(GetCryptographer()->encryptor());
|
| + other_cryptographer.AddKey(old_key);
|
| + WriteTransaction trans(FROM_HERE, user_share());
|
| + WriteNode nigori_node(&trans);
|
| + ASSERT_EQ(nigori_node.InitByTagLookup(kNigoriTag), BaseNode::INIT_OK);
|
| + sync_pb::NigoriSpecifics nigori;
|
| + other_cryptographer.GetKeys(nigori.mutable_encryption_keybag());
|
| + nigori.set_keybag_is_frozen(false);
|
| + nigori.set_encrypt_everything(false);
|
| + encryption_handler()->ApplyNigoriUpdate(nigori, trans.GetWrappedTrans());
|
| + nigori_node.SetNigoriSpecifics(nigori);
|
| + }
|
| + PumpLoop();
|
| +
|
| + // Verify we're still migrated and have proper encryption state.
|
| + EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
|
| + EXPECT_TRUE(GetCryptographer()->is_ready());
|
| + EXPECT_EQ(encryption_handler()->GetPassphraseType(), CUSTOM_PASSPHRASE);
|
| + EXPECT_TRUE(encryption_handler()->EncryptEverythingEnabled());
|
| + VerifyMigratedNigoriWithTimestamp(1, CUSTOM_PASSPHRASE, kCurKey);
|
| +}
|
| +
|
| +// Test that if we have a migrated nigori with a custom passphrase, then receive
|
| +// a migrated nigori with a keystore passphrase, we properly overwrite it with
|
| +// the current state.
|
| +TEST_F(SyncEncryptionHandlerImplTest, ReceiveOldMigratedNigori) {
|
| + const char kOldKey[] = "old";
|
| + const char kCurKey[] = "cur";
|
| + sync_pb::EncryptedData encrypted;
|
| + KeyParams old_key = {"localhost", "dummy", kOldKey};
|
| + KeyParams cur_key = {"localhost", "dummy", kCurKey};
|
| + KeyParams keystore_key = {"localhost", "dummy", kKeystoreKey};
|
| + GetCryptographer()->AddKey(old_key);
|
| + GetCryptographer()->AddKey(cur_key);
|
| +
|
| + // Build a migrated nigori with full encryption.
|
| + {
|
| + WriteTransaction trans(FROM_HERE, user_share());
|
| + WriteNode nigori_node(&trans);
|
| + ASSERT_EQ(nigori_node.InitByTagLookup(kNigoriTag), BaseNode::INIT_OK);
|
| + sync_pb::NigoriSpecifics nigori;
|
| + GetCryptographer()->GetKeys(nigori.mutable_encryption_keybag());
|
| + nigori.set_keybag_is_frozen(true);
|
| + nigori.set_keystore_migration_time(1);
|
| + nigori.set_passphrase_type(sync_pb::NigoriSpecifics::CUSTOM_PASSPHRASE);
|
| + nigori.set_encrypt_everything(true);
|
| + nigori_node.SetNigoriSpecifics(nigori);
|
| + }
|
| +
|
| + EXPECT_CALL(*observer(),
|
| + OnPassphraseTypeChanged(CUSTOM_PASSPHRASE));
|
| + EXPECT_CALL(*observer(),
|
| + OnCryptographerStateChanged(_));
|
| + EXPECT_CALL(*observer(),
|
| + OnEncryptedTypesChanged(_, true)).Times(2);
|
| + EXPECT_CALL(*observer(),
|
| + OnEncryptionComplete());
|
| + encryption_handler()->Init();
|
| + EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
|
| + EXPECT_TRUE(GetCryptographer()->is_ready());
|
| + EXPECT_EQ(encryption_handler()->GetPassphraseType(), CUSTOM_PASSPHRASE);
|
| + EXPECT_TRUE(encryption_handler()->EncryptEverythingEnabled());
|
| + VerifyMigratedNigoriWithTimestamp(1, CUSTOM_PASSPHRASE, kCurKey);
|
| +
|
| + {
|
| + EXPECT_CALL(*observer(),
|
| + OnBootstrapTokenUpdated(_, KEYSTORE_BOOTSTRAP_TOKEN));
|
| + ReadTransaction trans(FROM_HERE, user_share());
|
| + encryption_handler()->SetKeystoreKey(kKeystoreKey, trans.GetWrappedTrans());
|
| + }
|
| + Mock::VerifyAndClearExpectations(observer());
|
| +
|
| + // Now build an old keystore nigori node with old encrypted types. We should
|
| + // properly overwrite it with the migrated + encrypt everything state.
|
| + EXPECT_CALL(*observer(),
|
| + OnCryptographerStateChanged(_));
|
| + {
|
| + WriteTransaction trans(FROM_HERE, user_share());
|
| + WriteNode nigori_node(&trans);
|
| + ASSERT_EQ(nigori_node.InitByTagLookup(kNigoriTag), BaseNode::INIT_OK);
|
| + sync_pb::NigoriSpecifics nigori;
|
| + Cryptographer other_cryptographer(GetCryptographer()->encryptor());
|
| + other_cryptographer.AddKey(old_key);
|
| + encryption_handler()->GetKeystoreDecryptor(
|
| + other_cryptographer,
|
| + kKeystoreKey,
|
| + nigori.mutable_keystore_decryptor_token());
|
| + other_cryptographer.GetKeys(nigori.mutable_encryption_keybag());
|
| + nigori.set_keybag_is_frozen(true);
|
| + nigori.set_encrypt_everything(false);
|
| + nigori.set_passphrase_type(sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE);
|
| + nigori.set_keystore_migration_time(1);
|
| + encryption_handler()->ApplyNigoriUpdate(nigori, trans.GetWrappedTrans());
|
| + nigori_node.SetNigoriSpecifics(nigori);
|
| + }
|
| + PumpLoop();
|
| +
|
| + // Verify we're still migrated and have proper encryption state.
|
| + EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
|
| + EXPECT_TRUE(GetCryptographer()->is_ready());
|
| + EXPECT_EQ(encryption_handler()->GetPassphraseType(), CUSTOM_PASSPHRASE);
|
| + EXPECT_TRUE(encryption_handler()->EncryptEverythingEnabled());
|
| + VerifyMigratedNigoriWithTimestamp(1, CUSTOM_PASSPHRASE, kCurKey);
|
| +}
|
| +
|
| +// Test that if we receive the keystore key after receiving a migrated nigori
|
| +// node, we properly use the keystore decryptor token to decrypt the keybag.
|
| +TEST_F(SyncEncryptionHandlerImplTest, SetKeystoreAfterReceivingMigratedNigori) {
|
| + const char kCurKey[] = "cur";
|
| + sync_pb::EncryptedData keystore_decryptor_token;
|
| + Cryptographer other_cryptographer(GetCryptographer()->encryptor());
|
| + KeyParams cur_key = {"localhost", "dummy", kCurKey};
|
| + other_cryptographer.AddKey(cur_key);
|
| + EXPECT_TRUE(other_cryptographer.is_ready());
|
| + EXPECT_TRUE(encryption_handler()->GetKeystoreDecryptor(
|
| + other_cryptographer,
|
| + kKeystoreKey,
|
| + &keystore_decryptor_token));
|
| + EXPECT_FALSE(encryption_handler()->MigratedToKeystore());
|
| + EXPECT_FALSE(GetCryptographer()->is_ready());
|
| + EXPECT_NE(encryption_handler()->GetPassphraseType(), KEYSTORE_PASSPHRASE);
|
| +
|
| + // Now build a nigori node with the generated keystore decryptor token and
|
| + // initialize the encryption handler with it. The cryptographer should be
|
| + // initialized properly to decrypt both kCurKey and kKeystoreKey.
|
| + {
|
| + WriteTransaction trans(FROM_HERE, user_share());
|
| + WriteNode nigori_node(&trans);
|
| + ASSERT_EQ(nigori_node.InitByTagLookup(kNigoriTag), BaseNode::INIT_OK);
|
| + sync_pb::NigoriSpecifics nigori;
|
| + nigori.mutable_keystore_decryptor_token()->CopyFrom(
|
| + keystore_decryptor_token);
|
| + other_cryptographer.GetKeys(nigori.mutable_encryption_keybag());
|
| + nigori.set_keybag_is_frozen(true);
|
| + nigori.set_keystore_migration_time(1);
|
| + nigori.set_passphrase_type(sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE);
|
| +
|
| + EXPECT_CALL(*observer(),
|
| + OnPassphraseTypeChanged(KEYSTORE_PASSPHRASE));
|
| + EXPECT_CALL(*observer(),
|
| + OnCryptographerStateChanged(_));
|
| + EXPECT_CALL(*observer(),
|
| + OnPassphraseRequired(_, _));
|
| + encryption_handler()->ApplyNigoriUpdate(nigori, trans.GetWrappedTrans());
|
| + nigori_node.SetNigoriSpecifics(nigori);
|
| + }
|
| + // Run any tasks posted via AppplyNigoriUpdate.
|
| + PumpLoop();
|
| + EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
|
| + EXPECT_TRUE(GetCryptographer()->has_pending_keys());
|
| + EXPECT_EQ(encryption_handler()->GetPassphraseType(), KEYSTORE_PASSPHRASE);
|
| + EXPECT_FALSE(encryption_handler()->EncryptEverythingEnabled());
|
| + Mock::VerifyAndClearExpectations(observer());
|
| +
|
| + EXPECT_CALL(*observer(),
|
| + OnCryptographerStateChanged(_));
|
| + EXPECT_CALL(*observer(),
|
| + OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN));
|
| + {
|
| + EXPECT_CALL(*observer(),
|
| + OnBootstrapTokenUpdated(_, KEYSTORE_BOOTSTRAP_TOKEN));
|
| + ReadTransaction trans(FROM_HERE, user_share());
|
| + encryption_handler()->SetKeystoreKey(kKeystoreKey, trans.GetWrappedTrans());
|
| + }
|
| + PumpLoop();
|
| + EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
|
| + EXPECT_TRUE(GetCryptographer()->is_ready());
|
| + EXPECT_EQ(encryption_handler()->GetPassphraseType(), KEYSTORE_PASSPHRASE);
|
| + EXPECT_FALSE(encryption_handler()->EncryptEverythingEnabled());
|
| + VerifyMigratedNigoriWithTimestamp(1, KEYSTORE_PASSPHRASE, kCurKey);
|
| +
|
| + // Check that the cryptographer still encrypts with the current key.
|
| + sync_pb::EncryptedData current_encrypted;
|
| + other_cryptographer.EncryptString("string", ¤t_encrypted);
|
| + EXPECT_TRUE(GetCryptographer()->CanDecryptUsingDefaultKey(current_encrypted));
|
| +
|
| + // Check that the cryptographer can decrypt keystore key based encryption.
|
| + Cryptographer keystore_cryptographer(GetCryptographer()->encryptor());
|
| + KeyParams keystore_key = {"localhost", "dummy", kKeystoreKey};
|
| + keystore_cryptographer.AddKey(keystore_key);
|
| + sync_pb::EncryptedData keystore_encrypted;
|
| + keystore_cryptographer.EncryptString("string", &keystore_encrypted);
|
| + EXPECT_TRUE(GetCryptographer()->CanDecrypt(keystore_encrypted));
|
| +}
|
| +
|
| +// Test that after receiving a migrated nigori and decrypting it using the
|
| +// keystore key, we can then switch to a custom passphrase. The nigori should
|
| +// remain migrated and encrypt everything should be enabled.
|
| +TEST_F(SyncEncryptionHandlerImplTest, SetCustomPassAfterMigration) {
|
| + const char kOldKey[] = "old";
|
| + sync_pb::EncryptedData keystore_decryptor_token;
|
| + Cryptographer other_cryptographer(GetCryptographer()->encryptor());
|
| + KeyParams cur_key = {"localhost", "dummy", kOldKey};
|
| + other_cryptographer.AddKey(cur_key);
|
| + EXPECT_TRUE(other_cryptographer.is_ready());
|
| + EXPECT_TRUE(encryption_handler()->GetKeystoreDecryptor(
|
| + other_cryptographer,
|
| + kKeystoreKey,
|
| + &keystore_decryptor_token));
|
| +
|
| + // Build a nigori node with the generated keystore decryptor token and
|
| + // initialize the encryption handler with it. The cryptographer should be
|
| + // initialized properly to decrypt both kOldKey and kKeystoreKey.
|
| + {
|
| + WriteTransaction trans(FROM_HERE, user_share());
|
| + WriteNode nigori_node(&trans);
|
| + ASSERT_EQ(nigori_node.InitByTagLookup(kNigoriTag), BaseNode::INIT_OK);
|
| + sync_pb::NigoriSpecifics nigori;
|
| + nigori.mutable_keystore_decryptor_token()->CopyFrom(
|
| + keystore_decryptor_token);
|
| + other_cryptographer.GetKeys(nigori.mutable_encryption_keybag());
|
| + nigori.set_keybag_is_frozen(true);
|
| + nigori.set_keystore_migration_time(1);
|
| + nigori.set_passphrase_type(sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE);
|
| + nigori_node.SetNigoriSpecifics(nigori);
|
| + EXPECT_CALL(*observer(),
|
| + OnBootstrapTokenUpdated(_, KEYSTORE_BOOTSTRAP_TOKEN));
|
| + encryption_handler()->SetKeystoreKey(kKeystoreKey, trans.GetWrappedTrans());
|
| + }
|
| +
|
| + EXPECT_CALL(*observer(),
|
| + OnPassphraseTypeChanged(KEYSTORE_PASSPHRASE));
|
| + EXPECT_CALL(*observer(),
|
| + OnCryptographerStateChanged(_)).Times(2);
|
| + EXPECT_CALL(*observer(),
|
| + OnEncryptedTypesChanged(_, false));
|
| + EXPECT_CALL(*observer(),
|
| + OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN));
|
| + EXPECT_CALL(*observer(),
|
| + OnEncryptionComplete());
|
| + encryption_handler()->Init();
|
| + EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
|
| + EXPECT_TRUE(GetCryptographer()->is_ready());
|
| + EXPECT_EQ(encryption_handler()->GetPassphraseType(), KEYSTORE_PASSPHRASE);
|
| + EXPECT_FALSE(encryption_handler()->EncryptEverythingEnabled());
|
| + Mock::VerifyAndClearExpectations(observer());
|
| +
|
| + const char kNewKey[] = "new_key";
|
| + EXPECT_CALL(*observer(),
|
| + OnCryptographerStateChanged(_));
|
| + EXPECT_CALL(*observer(),
|
| + OnPassphraseTypeChanged(CUSTOM_PASSPHRASE));
|
| + EXPECT_CALL(*observer(),
|
| + OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN));
|
| + EXPECT_CALL(*observer(),
|
| + OnPassphraseAccepted());
|
| + EXPECT_CALL(*observer(),
|
| + OnEncryptedTypesChanged(_, true));
|
| + EXPECT_CALL(*observer(),
|
| + OnEncryptionComplete()).Times(2);
|
| + encryption_handler()->SetEncryptionPassphrase(kNewKey, true);
|
| + EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
|
| + EXPECT_TRUE(GetCryptographer()->is_ready());
|
| + EXPECT_EQ(encryption_handler()->GetPassphraseType(), CUSTOM_PASSPHRASE);
|
| + EXPECT_TRUE(encryption_handler()->EncryptEverythingEnabled());
|
| + VerifyMigratedNigoriWithTimestamp(1, CUSTOM_PASSPHRASE, kNewKey);
|
| +
|
| + // Check that the cryptographer can decrypt the old key.
|
| + sync_pb::EncryptedData old_encrypted;
|
| + other_cryptographer.EncryptString("string", &old_encrypted);
|
| + EXPECT_TRUE(GetCryptographer()->CanDecrypt(old_encrypted));
|
| +
|
| + // Check that the cryptographer can decrypt keystore key based encryption.
|
| + Cryptographer keystore_cryptographer(GetCryptographer()->encryptor());
|
| + KeyParams keystore_key = {"localhost", "dummy", kKeystoreKey};
|
| + keystore_cryptographer.AddKey(keystore_key);
|
| + sync_pb::EncryptedData keystore_encrypted;
|
| + keystore_cryptographer.EncryptString("string", &keystore_encrypted);
|
| + EXPECT_TRUE(GetCryptographer()->CanDecrypt(keystore_encrypted));
|
| +
|
| + // Check the the cryptographer is encrypting with the new key.
|
| + KeyParams new_key = {"localhost", "dummy", kNewKey};
|
| + Cryptographer new_cryptographer(GetCryptographer()->encryptor());
|
| + new_cryptographer.AddKey(new_key);
|
| + sync_pb::EncryptedData new_encrypted;
|
| + new_cryptographer.EncryptString("string", &new_encrypted);
|
| + EXPECT_TRUE(GetCryptographer()->CanDecryptUsingDefaultKey(new_encrypted));
|
| +}
|
| +
|
| +// Test that if a client without a keystore key (e.g. one without keystore
|
| +// encryption enabled) receives a migrated nigori and then attempts to set a
|
| +// custom passphrase, it also enables encrypt everything. The nigori node
|
| +// should remain migrated.
|
| +TEST_F(SyncEncryptionHandlerImplTest,
|
| + SetCustomPassAfterMigrationNoKeystoreKey) {
|
| + const char kOldKey[] = "old";
|
| + sync_pb::EncryptedData keystore_decryptor_token;
|
| + Cryptographer other_cryptographer(GetCryptographer()->encryptor());
|
| + KeyParams cur_key = {"localhost", "dummy", kOldKey};
|
| + other_cryptographer.AddKey(cur_key);
|
| + KeyParams keystore_key = {"localhost", "dummy", kKeystoreKey};
|
| + other_cryptographer.AddNonDefaultKey(keystore_key);
|
| + EXPECT_TRUE(other_cryptographer.is_ready());
|
| + EXPECT_TRUE(encryption_handler()->GetKeystoreDecryptor(
|
| + other_cryptographer,
|
| + kKeystoreKey,
|
| + &keystore_decryptor_token));
|
| +
|
| + // Build a nigori node with the generated keystore decryptor token and
|
| + // initialize the encryption handler with it. The cryptographer will have
|
| + // pending keys until we provide the decryption passphrase.
|
| + {
|
| + WriteTransaction trans(FROM_HERE, user_share());
|
| + WriteNode nigori_node(&trans);
|
| + ASSERT_EQ(nigori_node.InitByTagLookup(kNigoriTag), BaseNode::INIT_OK);
|
| + sync_pb::NigoriSpecifics nigori;
|
| + nigori.mutable_keystore_decryptor_token()->CopyFrom(
|
| + keystore_decryptor_token);
|
| + other_cryptographer.GetKeys(nigori.mutable_encryption_keybag());
|
| + nigori.set_keybag_is_frozen(true);
|
| + nigori.set_keystore_migration_time(1);
|
| + nigori.set_passphrase_type(sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE);
|
| + nigori_node.SetNigoriSpecifics(nigori);
|
| + }
|
| +
|
| + EXPECT_CALL(*observer(),
|
| + OnPassphraseRequired(_, _));
|
| + EXPECT_CALL(*observer(),
|
| + OnPassphraseTypeChanged(KEYSTORE_PASSPHRASE));
|
| + EXPECT_CALL(*observer(),
|
| + OnCryptographerStateChanged(_));
|
| + EXPECT_CALL(*observer(),
|
| + OnEncryptedTypesChanged(_, false));
|
| + encryption_handler()->Init();
|
| + EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
|
| + EXPECT_TRUE(GetCryptographer()->has_pending_keys());
|
| + EXPECT_EQ(encryption_handler()->GetPassphraseType(), KEYSTORE_PASSPHRASE);
|
| + EXPECT_FALSE(encryption_handler()->EncryptEverythingEnabled());
|
| + Mock::VerifyAndClearExpectations(observer());
|
| +
|
| + EXPECT_CALL(*observer(),
|
| + OnPassphraseAccepted());
|
| + EXPECT_CALL(*observer(),
|
| + OnCryptographerStateChanged(_));
|
| + EXPECT_CALL(*observer(),
|
| + OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN));
|
| + EXPECT_CALL(*observer(),
|
| + OnEncryptionComplete());
|
| + encryption_handler()->SetDecryptionPassphrase(kOldKey);
|
| + EXPECT_TRUE(GetCryptographer()->is_ready());
|
| + EXPECT_FALSE(encryption_handler()->EncryptEverythingEnabled());
|
| + Mock::VerifyAndClearExpectations(observer());
|
| +
|
| + const char kNewKey[] = "new_key";
|
| + EXPECT_CALL(*observer(),
|
| + OnCryptographerStateChanged(_));
|
| + EXPECT_CALL(*observer(),
|
| + OnPassphraseTypeChanged(CUSTOM_PASSPHRASE));
|
| + EXPECT_CALL(*observer(),
|
| + OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN));
|
| + EXPECT_CALL(*observer(),
|
| + OnPassphraseAccepted());
|
| + EXPECT_CALL(*observer(),
|
| + OnEncryptedTypesChanged(_, true));
|
| + EXPECT_CALL(*observer(),
|
| + OnEncryptionComplete()).Times(2);
|
| + encryption_handler()->SetEncryptionPassphrase(kNewKey, true);
|
| + EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
|
| + EXPECT_TRUE(GetCryptographer()->is_ready());
|
| + EXPECT_EQ(encryption_handler()->GetPassphraseType(), CUSTOM_PASSPHRASE);
|
| + EXPECT_TRUE(encryption_handler()->EncryptEverythingEnabled());
|
| + VerifyMigratedNigoriWithTimestamp(1, CUSTOM_PASSPHRASE, kNewKey);
|
| +
|
| + // Check that the cryptographer can decrypt the old key.
|
| + sync_pb::EncryptedData old_encrypted;
|
| + other_cryptographer.EncryptString("string", &old_encrypted);
|
| + EXPECT_TRUE(GetCryptographer()->CanDecrypt(old_encrypted));
|
| +
|
| + // Check that the cryptographer can still decrypt keystore key based
|
| + // encryption (should have been extracted from the encryption keybag).
|
| + Cryptographer keystore_cryptographer(GetCryptographer()->encryptor());
|
| + keystore_cryptographer.AddKey(keystore_key);
|
| + sync_pb::EncryptedData keystore_encrypted;
|
| + keystore_cryptographer.EncryptString("string", &keystore_encrypted);
|
| + EXPECT_TRUE(GetCryptographer()->CanDecrypt(keystore_encrypted));
|
| +
|
| + // Check the the cryptographer is encrypting with the new key.
|
| + KeyParams new_key = {"localhost", "dummy", kNewKey};
|
| + Cryptographer new_cryptographer(GetCryptographer()->encryptor());
|
| + new_cryptographer.AddKey(new_key);
|
| + sync_pb::EncryptedData new_encrypted;
|
| + new_cryptographer.EncryptString("string", &new_encrypted);
|
| + EXPECT_TRUE(GetCryptographer()->CanDecryptUsingDefaultKey(new_encrypted));
|
| +}
|
| +
|
| +// Test that if a client without a keystore key (e.g. one without keystore
|
| +// encryption enabled) receives a migrated nigori and then attempts to set a
|
| +// new implicit passphrase, we do not modify the nigori node (the implicit
|
| +// passphrase is dropped).
|
| +TEST_F(SyncEncryptionHandlerImplTest,
|
| + SetImplicitPassAfterMigrationNoKeystoreKey) {
|
| + const char kOldKey[] = "old";
|
| + sync_pb::EncryptedData keystore_decryptor_token;
|
| + Cryptographer other_cryptographer(GetCryptographer()->encryptor());
|
| + KeyParams cur_key = {"localhost", "dummy", kOldKey};
|
| + other_cryptographer.AddKey(cur_key);
|
| + KeyParams keystore_key = {"localhost", "dummy", kKeystoreKey};
|
| + other_cryptographer.AddNonDefaultKey(keystore_key);
|
| + EXPECT_TRUE(other_cryptographer.is_ready());
|
| + EXPECT_TRUE(encryption_handler()->GetKeystoreDecryptor(
|
| + other_cryptographer,
|
| + kKeystoreKey,
|
| + &keystore_decryptor_token));
|
| +
|
| + // Build a nigori node with the generated keystore decryptor token and
|
| + // initialize the encryption handler with it. The cryptographer will have
|
| + // pending keys until we provide the decryption passphrase.
|
| + {
|
| + WriteTransaction trans(FROM_HERE, user_share());
|
| + WriteNode nigori_node(&trans);
|
| + ASSERT_EQ(nigori_node.InitByTagLookup(kNigoriTag), BaseNode::INIT_OK);
|
| + sync_pb::NigoriSpecifics nigori;
|
| + nigori.mutable_keystore_decryptor_token()->CopyFrom(
|
| + keystore_decryptor_token);
|
| + other_cryptographer.GetKeys(nigori.mutable_encryption_keybag());
|
| + nigori.set_keybag_is_frozen(true);
|
| + nigori.set_keystore_migration_time(1);
|
| + nigori.set_passphrase_type(sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE);
|
| + nigori_node.SetNigoriSpecifics(nigori);
|
| + }
|
| +
|
| + EXPECT_CALL(*observer(),
|
| + OnPassphraseRequired(_, _));
|
| + EXPECT_CALL(*observer(),
|
| + OnPassphraseTypeChanged(KEYSTORE_PASSPHRASE));
|
| + EXPECT_CALL(*observer(),
|
| + OnCryptographerStateChanged(_));
|
| + EXPECT_CALL(*observer(),
|
| + OnEncryptedTypesChanged(_, false));
|
| + encryption_handler()->Init();
|
| + EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
|
| + EXPECT_TRUE(GetCryptographer()->has_pending_keys());
|
| + EXPECT_EQ(encryption_handler()->GetPassphraseType(), KEYSTORE_PASSPHRASE);
|
| + EXPECT_FALSE(encryption_handler()->EncryptEverythingEnabled());
|
| + Mock::VerifyAndClearExpectations(observer());
|
| +
|
| + EXPECT_CALL(*observer(),
|
| + OnPassphraseAccepted());
|
| + EXPECT_CALL(*observer(),
|
| + OnCryptographerStateChanged(_));
|
| + EXPECT_CALL(*observer(),
|
| + OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN));
|
| + EXPECT_CALL(*observer(),
|
| + OnEncryptionComplete());
|
| + encryption_handler()->SetDecryptionPassphrase(kOldKey);
|
| + EXPECT_TRUE(GetCryptographer()->is_ready());
|
| + EXPECT_FALSE(encryption_handler()->EncryptEverythingEnabled());
|
| + Mock::VerifyAndClearExpectations(observer());
|
| +
|
| + // Should get dropped on the floor silently.
|
| + const char kNewKey[] = "new_key";
|
| + encryption_handler()->SetEncryptionPassphrase(kNewKey, false);
|
| + EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
|
| + EXPECT_TRUE(GetCryptographer()->is_ready());
|
| + EXPECT_EQ(encryption_handler()->GetPassphraseType(), KEYSTORE_PASSPHRASE);
|
| + EXPECT_FALSE(encryption_handler()->EncryptEverythingEnabled());
|
| + VerifyMigratedNigoriWithTimestamp(1, KEYSTORE_PASSPHRASE, kOldKey);
|
| +
|
| + // Check that the cryptographer can decrypt the old key.
|
| + sync_pb::EncryptedData old_encrypted;
|
| + other_cryptographer.EncryptString("string", &old_encrypted);
|
| + EXPECT_TRUE(GetCryptographer()->CanDecryptUsingDefaultKey(old_encrypted));
|
| +
|
| + // Check that the cryptographer can still decrypt keystore key based
|
| + // encryption (due to extracting the keystore key from the encryption keybag).
|
| + Cryptographer keystore_cryptographer(GetCryptographer()->encryptor());
|
| + keystore_cryptographer.AddKey(keystore_key);
|
| + sync_pb::EncryptedData keystore_encrypted;
|
| + keystore_cryptographer.EncryptString("string", &keystore_encrypted);
|
| + EXPECT_TRUE(GetCryptographer()->CanDecrypt(keystore_encrypted));
|
| +
|
| + // Check the the cryptographer does not have the new key.
|
| + KeyParams new_key = {"localhost", "dummy", kNewKey};
|
| + Cryptographer new_cryptographer(GetCryptographer()->encryptor());
|
| + new_cryptographer.AddKey(new_key);
|
| + sync_pb::EncryptedData new_encrypted;
|
| + new_cryptographer.EncryptString("string", &new_encrypted);
|
| + EXPECT_FALSE(GetCryptographer()->CanDecryptUsingDefaultKey(new_encrypted));
|
| +}
|
| +
|
| +// Test that if a client without a keystore key (e.g. one without keystore
|
| +// encryption enabled) receives a migrated nigori in keystore passphrase state
|
| +// and then attempts to enable encrypt everything, we switch to a custom
|
| +// passphrase. The nigori should remain migrated.
|
| +TEST_F(SyncEncryptionHandlerImplTest,
|
| + MigrateOnEncryptEverythingKeystorePassphrase) {
|
| + const char kCurKey[] = "cur";
|
| + sync_pb::EncryptedData keystore_decryptor_token;
|
| + Cryptographer other_cryptographer(GetCryptographer()->encryptor());
|
| + KeyParams cur_key = {"localhost", "dummy", kCurKey};
|
| + other_cryptographer.AddKey(cur_key);
|
| + KeyParams keystore_key = {"localhost", "dummy", kKeystoreKey};
|
| + other_cryptographer.AddNonDefaultKey(keystore_key);
|
| + EXPECT_TRUE(other_cryptographer.is_ready());
|
| + EXPECT_TRUE(encryption_handler()->GetKeystoreDecryptor(
|
| + other_cryptographer,
|
| + kKeystoreKey,
|
| + &keystore_decryptor_token));
|
| +
|
| + // Build a nigori node with the generated keystore decryptor token and
|
| + // initialize the encryption handler with it. The cryptographer will have
|
| + // pending keys until we provide the decryption passphrase.
|
| + {
|
| + WriteTransaction trans(FROM_HERE, user_share());
|
| + WriteNode nigori_node(&trans);
|
| + ASSERT_EQ(nigori_node.InitByTagLookup(kNigoriTag), BaseNode::INIT_OK);
|
| + sync_pb::NigoriSpecifics nigori;
|
| + nigori.mutable_keystore_decryptor_token()->CopyFrom(
|
| + keystore_decryptor_token);
|
| + other_cryptographer.GetKeys(nigori.mutable_encryption_keybag());
|
| + nigori.set_keybag_is_frozen(true);
|
| + nigori.set_keystore_migration_time(1);
|
| + nigori.set_passphrase_type(sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE);
|
| + nigori_node.SetNigoriSpecifics(nigori);
|
| + }
|
| + EXPECT_CALL(*observer(),
|
| + OnPassphraseRequired(_, _));
|
| + EXPECT_CALL(*observer(),
|
| + OnPassphraseTypeChanged(KEYSTORE_PASSPHRASE));
|
| + EXPECT_CALL(*observer(),
|
| + OnCryptographerStateChanged(_));
|
| + EXPECT_CALL(*observer(),
|
| + OnEncryptedTypesChanged(_, false));
|
| + encryption_handler()->Init();
|
| + EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
|
| + EXPECT_TRUE(GetCryptographer()->has_pending_keys());
|
| + EXPECT_EQ(encryption_handler()->GetPassphraseType(), KEYSTORE_PASSPHRASE);
|
| + EXPECT_FALSE(encryption_handler()->EncryptEverythingEnabled());
|
| + Mock::VerifyAndClearExpectations(observer());
|
| +
|
| + EXPECT_CALL(*observer(),
|
| + OnPassphraseAccepted());
|
| + EXPECT_CALL(*observer(),
|
| + OnCryptographerStateChanged(_));
|
| + EXPECT_CALL(*observer(),
|
| + OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN));
|
| + EXPECT_CALL(*observer(),
|
| + OnEncryptionComplete());
|
| + encryption_handler()->SetDecryptionPassphrase(kCurKey);
|
| + Mock::VerifyAndClearExpectations(observer());
|
| +
|
| + EXPECT_CALL(*observer(),
|
| + OnPassphraseTypeChanged(FROZEN_IMPLICIT_PASSPHRASE));
|
| + EXPECT_CALL(*observer(),
|
| + OnEncryptionComplete());
|
| + EXPECT_CALL(*observer(),
|
| + OnEncryptedTypesChanged(_, true));
|
| + encryption_handler()->EnableEncryptEverything();
|
| + Mock::VerifyAndClearExpectations(observer());
|
| +
|
| + EXPECT_TRUE(encryption_handler()->MigratedToKeystore());
|
| + EXPECT_TRUE(GetCryptographer()->is_ready());
|
| + EXPECT_EQ(FROZEN_IMPLICIT_PASSPHRASE,
|
| + encryption_handler()->GetPassphraseType());
|
| + EXPECT_TRUE(encryption_handler()->EncryptEverythingEnabled());
|
| + VerifyMigratedNigoriWithTimestamp(1, FROZEN_IMPLICIT_PASSPHRASE, kCurKey);
|
| +
|
| + // Check that the cryptographer is encrypting using the frozen current key.
|
| + sync_pb::EncryptedData current_encrypted;
|
| + other_cryptographer.EncryptString("string", ¤t_encrypted);
|
| + EXPECT_TRUE(GetCryptographer()->CanDecryptUsingDefaultKey(current_encrypted));
|
| +
|
| + // Check that the cryptographer can still decrypt keystore key based
|
| + // encryption (due to extracting the keystore key from the encryption keybag).
|
| + Cryptographer keystore_cryptographer(GetCryptographer()->encryptor());
|
| + keystore_cryptographer.AddKey(keystore_key);
|
| + sync_pb::EncryptedData keystore_encrypted;
|
| + keystore_cryptographer.EncryptString("string", &keystore_encrypted);
|
| + EXPECT_TRUE(GetCryptographer()->CanDecrypt(keystore_encrypted));
|
| +}
|
| +
|
| } // namespace syncer
|
|
|