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 |
deleted file mode 100644 |
index 730116106a8190f6046243da6daae4353724651f..0000000000000000000000000000000000000000 |
--- a/sync/internal_api/sync_encryption_handler_impl_unittest.cc |
+++ /dev/null |
@@ -1,2494 +0,0 @@ |
-// Copyright 2012 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "sync/internal_api/sync_encryption_handler_impl.h" |
- |
-#include <stdint.h> |
- |
-#include <memory> |
-#include <string> |
- |
-#include "base/base64.h" |
-#include "base/json/json_string_value_serializer.h" |
-#include "base/run_loop.h" |
-#include "base/tracked_objects.h" |
-#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/test/test_user_share.h" |
-#include "sync/internal_api/public/write_node.h" |
-#include "sync/internal_api/public/write_transaction.h" |
-#include "sync/protocol/nigori_specifics.pb.h" |
-#include "sync/protocol/sync.pb.h" |
-#include "sync/syncable/entry.h" |
-#include "sync/syncable/mutable_entry.h" |
-#include "sync/syncable/syncable_write_transaction.h" |
-#include "sync/test/engine/test_id_factory.h" |
-#include "sync/test/fake_encryptor.h" |
-#include "sync/util/cryptographer.h" |
-#include "testing/gmock/include/gmock/gmock.h" |
-#include "testing/gtest/include/gtest/gtest.h" |
- |
-namespace syncer { |
- |
-namespace { |
- |
-using ::testing::_; |
-using ::testing::AnyNumber; |
-using ::testing::AtLeast; |
-using ::testing::Mock; |
-using ::testing::SaveArg; |
-using ::testing::StrictMock; |
- |
-// The raw keystore key the server sends. |
-static const char kRawKeystoreKey[] = "keystore_key"; |
-// Base64 encoded version of |kRawKeystoreKey|. |
-static const char kKeystoreKey[] = "a2V5c3RvcmVfa2V5"; |
- |
-class SyncEncryptionHandlerObserverMock |
- : public SyncEncryptionHandler::Observer { |
- public: |
- MOCK_METHOD2(OnPassphraseRequired, |
- void(PassphraseRequiredReason, |
- const sync_pb::EncryptedData&)); // NOLINT |
- MOCK_METHOD0(OnPassphraseAccepted, void()); // NOLINT |
- MOCK_METHOD2(OnBootstrapTokenUpdated, |
- void(const std::string&, BootstrapTokenType type)); // NOLINT |
- MOCK_METHOD2(OnEncryptedTypesChanged, |
- void(ModelTypeSet, bool)); // NOLINT |
- MOCK_METHOD0(OnEncryptionComplete, void()); // NOLINT |
- MOCK_METHOD1(OnCryptographerStateChanged, void(Cryptographer*)); // NOLINT |
- MOCK_METHOD2(OnPassphraseTypeChanged, void(PassphraseType, |
- base::Time)); // NOLINT |
- MOCK_METHOD1(OnLocalSetPassphraseEncryption, |
- void(const SyncEncryptionHandler::NigoriState&)); // NOLINT |
-}; |
- |
-google::protobuf::RepeatedPtrField<google::protobuf::string> |
-BuildEncryptionKeyProto(const std::string& encryption_key) { |
- google::protobuf::RepeatedPtrField<google::protobuf::string> keys; |
- keys.Add()->assign(encryption_key); |
- return keys; |
-} |
- |
-} // namespace |
- |
-class SyncEncryptionHandlerImplTest : public ::testing::Test { |
- public: |
- SyncEncryptionHandlerImplTest() {} |
- virtual ~SyncEncryptionHandlerImplTest() {} |
- |
- virtual void SetUp() { |
- test_user_share_.SetUp(); |
- SetUpEncryption(); |
- CreateRootForType(NIGORI); |
- } |
- |
- virtual void TearDown() { |
- PumpLoop(); |
- test_user_share_.TearDown(); |
- } |
- |
- protected: |
- void SetUpEncryption() { |
- SetUpEncryptionWithKeyForBootstrapping(std::string()); |
- } |
- |
- void SetUpEncryptionWithKeyForBootstrapping( |
- const std::string& key_for_bootstrapping) { |
- encryption_handler_.reset(new SyncEncryptionHandlerImpl( |
- user_share(), &encryptor_, key_for_bootstrapping, |
- std::string() /* keystore key for bootstrapping */)); |
- encryption_handler_->AddObserver(&observer_); |
- } |
- |
- void CreateRootForType(ModelType model_type) { |
- syncer::syncable::Directory* directory = user_share()->directory.get(); |
- |
- std::string tag_name = ModelTypeToRootTag(model_type); |
- |
- syncable::WriteTransaction wtrans(FROM_HERE, syncable::UNITTEST, directory); |
- syncable::MutableEntry node(&wtrans, |
- syncable::CREATE, |
- model_type, |
- wtrans.root_id(), |
- tag_name); |
- node.PutUniqueServerTag(tag_name); |
- node.PutIsDir(true); |
- node.PutServerIsDir(false); |
- node.PutIsUnsynced(false); |
- node.PutIsUnappliedUpdate(false); |
- node.PutServerVersion(20); |
- node.PutBaseVersion(20); |
- node.PutIsDel(false); |
- node.PutId(ids_.MakeServer(tag_name)); |
- sync_pb::EntitySpecifics specifics; |
- syncer::AddDefaultFieldValue(model_type, &specifics); |
- node.PutSpecifics(specifics); |
- } |
- |
- void PumpLoop() { |
- base::RunLoop().RunUntilIdle(); |
- } |
- |
- // Getters for tests. |
- UserShare* user_share() { return test_user_share_.user_share(); } |
- SyncEncryptionHandlerImpl* encryption_handler() { |
- return encryption_handler_.get(); |
- } |
- SyncEncryptionHandlerObserverMock* observer() { return &observer_; } |
- Cryptographer* GetCryptographer() { |
- return encryption_handler_->GetCryptographerUnsafe(); |
- } |
- |
- void VerifyMigratedNigori(PassphraseType passphrase_type, |
- const std::string& passphrase) { |
- VerifyMigratedNigoriWithTimestamp(0, passphrase_type, passphrase); |
- } |
- |
- void VerifyMigratedNigoriWithTimestamp(int64_t migration_time, |
- PassphraseType passphrase_type, |
- const std::string& passphrase) { |
- ReadTransaction trans(FROM_HERE, user_share()); |
- ReadNode nigori_node(&trans); |
- ASSERT_EQ(nigori_node.InitTypeRoot(NIGORI), 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()); |
- if (!encryption_handler()->custom_passphrase_time().is_null()) { |
- EXPECT_EQ(nigori.custom_passphrase_time(), |
- TimeToProtoTime( |
- encryption_handler()->custom_passphrase_time())); |
- } |
- } 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())); |
- } |
- |
- sync_pb::NigoriSpecifics BuildMigratedNigori( |
- PassphraseType passphrase_type, |
- int64_t migration_time, |
- const std::string& default_passphrase, |
- const std::string& keystore_key) { |
- DCHECK_NE(passphrase_type, IMPLICIT_PASSPHRASE); |
- Cryptographer other_cryptographer(GetCryptographer()->encryptor()); |
- |
- std::string default_key = default_passphrase; |
- if (default_key.empty()) { |
- default_key = keystore_key; |
- } else { |
- KeyParams keystore_params = {"localhost", "dummy", keystore_key}; |
- other_cryptographer.AddKey(keystore_params); |
- } |
- KeyParams params = {"localhost", "dummy", default_key}; |
- other_cryptographer.AddKey(params); |
- EXPECT_TRUE(other_cryptographer.is_ready()); |
- |
- sync_pb::NigoriSpecifics nigori; |
- other_cryptographer.GetKeys(nigori.mutable_encryption_keybag()); |
- nigori.set_keybag_is_frozen(true); |
- nigori.set_keystore_migration_time(migration_time); |
- |
- if (passphrase_type == KEYSTORE_PASSPHRASE) { |
- sync_pb::EncryptedData keystore_decryptor_token; |
- EXPECT_TRUE(encryption_handler()->GetKeystoreDecryptor( |
- other_cryptographer, |
- keystore_key, |
- &keystore_decryptor_token)); |
- nigori.mutable_keystore_decryptor_token()->CopyFrom( |
- keystore_decryptor_token); |
- nigori.set_passphrase_type(sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE); |
- } else { |
- nigori.set_encrypt_everything(true); |
- nigori.set_passphrase_type( |
- passphrase_type == CUSTOM_PASSPHRASE ? |
- sync_pb::NigoriSpecifics::CUSTOM_PASSPHRASE : |
- sync_pb::NigoriSpecifics::FROZEN_IMPLICIT_PASSPHRASE); |
- } |
- return nigori; |
- } |
- |
- // Build a migrated nigori node with the specified default passphrase |
- // and keystore key and initialize the encryption handler with it. |
- void InitKeystoreMigratedNigori(int64_t migration_time, |
- const std::string& default_passphrase, |
- const std::string& keystore_key) { |
- { |
- WriteTransaction trans(FROM_HERE, user_share()); |
- WriteNode nigori_node(&trans); |
- ASSERT_EQ(nigori_node.InitTypeRoot(NIGORI), BaseNode::INIT_OK); |
- sync_pb::NigoriSpecifics nigori = BuildMigratedNigori( |
- KEYSTORE_PASSPHRASE, |
- migration_time, |
- default_passphrase, |
- keystore_key); |
- nigori_node.SetNigoriSpecifics(nigori); |
- } |
- |
- EXPECT_CALL(*observer(), |
- OnPassphraseTypeChanged(KEYSTORE_PASSPHRASE, _)); |
- EXPECT_CALL(*observer(), |
- OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)); |
- EXPECT_CALL(*observer(), |
- OnCryptographerStateChanged(_)).Times(AtLeast(1)); |
- EXPECT_CALL(*observer(), |
- OnEncryptedTypesChanged(_, false)); |
- EXPECT_CALL(*observer(), |
- OnEncryptionComplete()).Times(AtLeast(1)); |
- encryption_handler()->Init(); |
- EXPECT_TRUE(encryption_handler()->MigratedToKeystore()); |
- EXPECT_EQ(encryption_handler()->GetPassphraseType(), KEYSTORE_PASSPHRASE); |
- EXPECT_FALSE(encryption_handler()->IsEncryptEverythingEnabled()); |
- Mock::VerifyAndClearExpectations(observer()); |
- } |
- |
- // Build a migrated nigori node with the specified default passphrase |
- // as a custom passphrase. |
- void InitCustomPassMigratedNigori(int64_t migration_time, |
- const std::string& default_passphrase) { |
- { |
- WriteTransaction trans(FROM_HERE, user_share()); |
- WriteNode nigori_node(&trans); |
- ASSERT_EQ(nigori_node.InitTypeRoot(NIGORI), BaseNode::INIT_OK); |
- sync_pb::NigoriSpecifics nigori = BuildMigratedNigori( |
- CUSTOM_PASSPHRASE, |
- migration_time, |
- default_passphrase, |
- kKeystoreKey); |
- nigori_node.SetNigoriSpecifics(nigori); |
- } |
- |
- EXPECT_CALL(*observer(), |
- OnPassphraseTypeChanged(CUSTOM_PASSPHRASE, _)); |
- EXPECT_CALL(*observer(), |
- OnCryptographerStateChanged(_)).Times(AtLeast(1)); |
- EXPECT_CALL(*observer(), |
- OnEncryptedTypesChanged(_, true)).Times(AtLeast(1)); |
- EXPECT_CALL(*observer(), |
- OnEncryptionComplete()).Times(AtLeast(1)); |
- encryption_handler()->Init(); |
- EXPECT_TRUE(encryption_handler()->MigratedToKeystore()); |
- EXPECT_EQ(encryption_handler()->GetPassphraseType(), CUSTOM_PASSPHRASE); |
- EXPECT_TRUE(encryption_handler()->IsEncryptEverythingEnabled()); |
- Mock::VerifyAndClearExpectations(observer()); |
- } |
- |
- // Build an unmigrated nigori node with the specified passphrase and type and |
- // initialize the encryption handler with it. |
- void InitUnmigratedNigori(const std::string& default_passphrase, |
- PassphraseType passphrase_type) { |
- DCHECK_NE(passphrase_type, FROZEN_IMPLICIT_PASSPHRASE); |
- Cryptographer other_cryptographer(GetCryptographer()->encryptor()); |
- KeyParams default_key = {"localhost", "dummy", default_passphrase}; |
- other_cryptographer.AddKey(default_key); |
- EXPECT_TRUE(other_cryptographer.is_ready()); |
- |
- { |
- WriteTransaction trans(FROM_HERE, user_share()); |
- WriteNode nigori_node(&trans); |
- ASSERT_EQ(nigori_node.InitTypeRoot(NIGORI), BaseNode::INIT_OK); |
- sync_pb::NigoriSpecifics nigori; |
- other_cryptographer.GetKeys(nigori.mutable_encryption_keybag()); |
- nigori.set_keybag_is_frozen(passphrase_type == CUSTOM_PASSPHRASE); |
- nigori_node.SetNigoriSpecifics(nigori); |
- } |
- |
- if (passphrase_type != IMPLICIT_PASSPHRASE) { |
- EXPECT_CALL(*observer(), |
- OnPassphraseTypeChanged(passphrase_type, _)); |
- } |
- EXPECT_CALL(*observer(), |
- OnCryptographerStateChanged(_)).Times(AtLeast(1)); |
- EXPECT_CALL(*observer(), |
- OnEncryptedTypesChanged(_, false)); |
- encryption_handler()->Init(); |
- EXPECT_FALSE(encryption_handler()->MigratedToKeystore()); |
- EXPECT_EQ(encryption_handler()->GetPassphraseType(), passphrase_type); |
- EXPECT_FALSE(encryption_handler()->IsEncryptEverythingEnabled()); |
- Mock::VerifyAndClearExpectations(observer()); |
- } |
- |
- // Verify we can restore the SyncEncryptionHandler state using a saved |
- // |bootstrap_token| and |nigori_state|. |
- // |
- // |migration_time| is the time migration occurred. |
- // |
- // |passphrase| is the custom passphrase. |
- void VerifyRestoreAfterCustomPassphrase( |
- int64_t migration_time, |
- const std::string& passphrase, |
- const std::string& bootstrap_token, |
- const SyncEncryptionHandler::NigoriState& nigori_state, |
- PassphraseType passphrase_type) { |
- TearDown(); |
- test_user_share_.SetUp(); |
- SetUpEncryptionWithKeyForBootstrapping(bootstrap_token); |
- EXPECT_CALL(*observer(), OnCryptographerStateChanged(_)).Times(AnyNumber()); |
- EXPECT_CALL(*observer(), OnEncryptedTypesChanged(_, true)) |
- .Times(AnyNumber()); |
- EXPECT_CALL(*observer(), OnPassphraseTypeChanged(passphrase_type, _)); |
- EXPECT_CALL(*observer(), OnEncryptionComplete()); |
- encryption_handler()->RestoreNigori(nigori_state); |
- encryption_handler()->Init(); |
- Mock::VerifyAndClearExpectations(observer()); |
- VerifyMigratedNigoriWithTimestamp(migration_time, passphrase_type, |
- passphrase); |
- } |
- |
- protected: |
- TestUserShare test_user_share_; |
- FakeEncryptor encryptor_; |
- std::unique_ptr<SyncEncryptionHandlerImpl> encryption_handler_; |
- StrictMock<SyncEncryptionHandlerObserverMock> observer_; |
- TestIdFactory ids_; |
- base::MessageLoop message_loop_; |
-}; |
- |
-// Verify that the encrypted types are being written to and read from the |
-// nigori node properly. |
-TEST_F(SyncEncryptionHandlerImplTest, NigoriEncryptionTypes) { |
- sync_pb::NigoriSpecifics nigori; |
- |
- StrictMock<SyncEncryptionHandlerObserverMock> observer2; |
- SyncEncryptionHandlerImpl handler2(user_share(), &encryptor_, std::string(), |
- std::string() /* bootstrap tokens */); |
- handler2.AddObserver(&observer2); |
- |
- // Just set the sensitive types (shouldn't trigger any notifications). |
- ModelTypeSet encrypted_types(SyncEncryptionHandler::SensitiveTypes()); |
- { |
- WriteTransaction trans(FROM_HERE, user_share()); |
- encryption_handler()->MergeEncryptedTypes( |
- encrypted_types, |
- trans.GetWrappedTrans()); |
- encryption_handler()->UpdateNigoriFromEncryptedTypes( |
- &nigori, |
- trans.GetWrappedTrans()); |
- handler2.UpdateEncryptedTypesFromNigori(nigori, trans.GetWrappedTrans()); |
- } |
- EXPECT_EQ(encrypted_types, encryption_handler()->GetEncryptedTypesUnsafe()); |
- EXPECT_EQ(encrypted_types, handler2.GetEncryptedTypesUnsafe()); |
- |
- Mock::VerifyAndClearExpectations(observer()); |
- Mock::VerifyAndClearExpectations(&observer2); |
- |
- ModelTypeSet encrypted_user_types = EncryptableUserTypes(); |
- |
- EXPECT_CALL(*observer(), |
- OnEncryptedTypesChanged( |
- HasModelTypes(encrypted_user_types), false)); |
- EXPECT_CALL(observer2, |
- OnEncryptedTypesChanged( |
- HasModelTypes(encrypted_user_types), false)); |
- |
- // Set all encrypted types |
- encrypted_types = EncryptableUserTypes(); |
- { |
- WriteTransaction trans(FROM_HERE, user_share()); |
- encryption_handler()->MergeEncryptedTypes( |
- encrypted_types, |
- trans.GetWrappedTrans()); |
- encryption_handler()->UpdateNigoriFromEncryptedTypes( |
- &nigori, |
- trans.GetWrappedTrans()); |
- handler2.UpdateEncryptedTypesFromNigori(nigori, trans.GetWrappedTrans()); |
- } |
- EXPECT_EQ(encrypted_types, encryption_handler()->GetEncryptedTypesUnsafe()); |
- EXPECT_EQ(encrypted_types, handler2.GetEncryptedTypesUnsafe()); |
- |
- // Receiving an empty nigori should not reset any encrypted types or trigger |
- // an observer notification. |
- Mock::VerifyAndClearExpectations(observer()); |
- Mock::VerifyAndClearExpectations(&observer2); |
- nigori = sync_pb::NigoriSpecifics(); |
- { |
- WriteTransaction trans(FROM_HERE, user_share()); |
- handler2.UpdateEncryptedTypesFromNigori(nigori, trans.GetWrappedTrans()); |
- } |
- EXPECT_EQ(encrypted_types, encryption_handler()->GetEncryptedTypesUnsafe()); |
-} |
- |
-// Verify the encryption handler processes the encrypt everything field |
-// properly. |
-TEST_F(SyncEncryptionHandlerImplTest, EncryptEverythingExplicit) { |
- sync_pb::NigoriSpecifics nigori; |
- nigori.set_encrypt_everything(true); |
- |
- EXPECT_CALL(*observer(), |
- OnEncryptedTypesChanged( |
- HasModelTypes(EncryptableUserTypes()), true)); |
- |
- EXPECT_FALSE(encryption_handler()->IsEncryptEverythingEnabled()); |
- ModelTypeSet encrypted_types = |
- encryption_handler()->GetEncryptedTypesUnsafe(); |
- EXPECT_EQ(ModelTypeSet(PASSWORDS, WIFI_CREDENTIALS), encrypted_types); |
- |
- { |
- WriteTransaction trans(FROM_HERE, user_share()); |
- encryption_handler()->UpdateEncryptedTypesFromNigori( |
- nigori, |
- trans.GetWrappedTrans()); |
- } |
- |
- EXPECT_TRUE(encryption_handler()->IsEncryptEverythingEnabled()); |
- encrypted_types = encryption_handler()->GetEncryptedTypesUnsafe(); |
- EXPECT_TRUE(encrypted_types.HasAll(EncryptableUserTypes())); |
- |
- // Receiving the nigori node again shouldn't trigger another notification. |
- Mock::VerifyAndClearExpectations(observer()); |
- { |
- WriteTransaction trans(FROM_HERE, user_share()); |
- encryption_handler()->UpdateEncryptedTypesFromNigori( |
- nigori, |
- trans.GetWrappedTrans()); |
- } |
-} |
- |
-// Verify the encryption handler can detect an implicit encrypt everything state |
-// (from clients that failed to write the encrypt everything field). |
-TEST_F(SyncEncryptionHandlerImplTest, EncryptEverythingImplicit) { |
- sync_pb::NigoriSpecifics nigori; |
- nigori.set_encrypt_bookmarks(true); // Non-passwords = encrypt everything |
- |
- EXPECT_CALL(*observer(), |
- OnEncryptedTypesChanged( |
- HasModelTypes(EncryptableUserTypes()), true)); |
- |
- EXPECT_FALSE(encryption_handler()->IsEncryptEverythingEnabled()); |
- ModelTypeSet encrypted_types = |
- encryption_handler()->GetEncryptedTypesUnsafe(); |
- EXPECT_EQ(ModelTypeSet(PASSWORDS, WIFI_CREDENTIALS), encrypted_types); |
- |
- { |
- WriteTransaction trans(FROM_HERE, user_share()); |
- encryption_handler()->UpdateEncryptedTypesFromNigori( |
- nigori, |
- trans.GetWrappedTrans()); |
- } |
- |
- EXPECT_TRUE(encryption_handler()->IsEncryptEverythingEnabled()); |
- encrypted_types = encryption_handler()->GetEncryptedTypesUnsafe(); |
- EXPECT_TRUE(encrypted_types.HasAll(EncryptableUserTypes())); |
- |
- // Receiving a nigori node with encrypt everything explicitly set shouldn't |
- // trigger another notification. |
- Mock::VerifyAndClearExpectations(observer()); |
- nigori.set_encrypt_everything(true); |
- { |
- WriteTransaction trans(FROM_HERE, user_share()); |
- encryption_handler()->UpdateEncryptedTypesFromNigori( |
- nigori, |
- trans.GetWrappedTrans()); |
- } |
-} |
- |
-// Verify the encryption handler can deal with new versions treating new types |
-// as Sensitive, and that it does not consider this an implicit encrypt |
-// everything case. |
-TEST_F(SyncEncryptionHandlerImplTest, UnknownSensitiveTypes) { |
- sync_pb::NigoriSpecifics nigori; |
- nigori.set_encrypt_everything(false); |
- nigori.set_encrypt_bookmarks(true); |
- |
- ModelTypeSet expected_encrypted_types = |
- SyncEncryptionHandler::SensitiveTypes(); |
- expected_encrypted_types.Put(BOOKMARKS); |
- |
- EXPECT_CALL(*observer(), |
- OnEncryptedTypesChanged( |
- HasModelTypes(expected_encrypted_types), false)); |
- |
- EXPECT_FALSE(encryption_handler()->IsEncryptEverythingEnabled()); |
- ModelTypeSet encrypted_types = |
- encryption_handler()->GetEncryptedTypesUnsafe(); |
- EXPECT_EQ(ModelTypeSet(PASSWORDS, WIFI_CREDENTIALS), encrypted_types); |
- |
- { |
- WriteTransaction trans(FROM_HERE, user_share()); |
- encryption_handler()->UpdateEncryptedTypesFromNigori( |
- nigori, |
- trans.GetWrappedTrans()); |
- } |
- |
- EXPECT_FALSE(encryption_handler()->IsEncryptEverythingEnabled()); |
- encrypted_types = encryption_handler()->GetEncryptedTypesUnsafe(); |
- EXPECT_EQ(ModelTypeSet(BOOKMARKS, PASSWORDS, WIFI_CREDENTIALS), |
- encrypted_types); |
-} |
- |
-// Receive an old nigori with old encryption keys and encrypted types. We should |
-// not revert our default key or encrypted types, and should post a task to |
-// overwrite the existing nigori with the correct data. |
-TEST_F(SyncEncryptionHandlerImplTest, ReceiveOldNigori) { |
- KeyParams old_key = {"localhost", "dummy", "old"}; |
- KeyParams current_key = {"localhost", "dummy", "cur"}; |
- |
- // Data for testing encryption/decryption. |
- Cryptographer other_cryptographer(GetCryptographer()->encryptor()); |
- other_cryptographer.AddKey(old_key); |
- sync_pb::EntitySpecifics other_encrypted_specifics; |
- other_encrypted_specifics.mutable_bookmark()->set_title("title"); |
- other_cryptographer.Encrypt( |
- other_encrypted_specifics, |
- other_encrypted_specifics.mutable_encrypted()); |
- sync_pb::EntitySpecifics our_encrypted_specifics; |
- our_encrypted_specifics.mutable_bookmark()->set_title("title2"); |
- ModelTypeSet encrypted_types = EncryptableUserTypes(); |
- |
- // Set up the current encryption state (containing both keys and encrypt |
- // everything). |
- sync_pb::NigoriSpecifics current_nigori_specifics; |
- GetCryptographer()->AddKey(old_key); |
- GetCryptographer()->AddKey(current_key); |
- GetCryptographer()->Encrypt( |
- our_encrypted_specifics, |
- our_encrypted_specifics.mutable_encrypted()); |
- GetCryptographer()->GetKeys( |
- current_nigori_specifics.mutable_encryption_keybag()); |
- current_nigori_specifics.set_encrypt_everything(true); |
- |
- EXPECT_CALL(*observer(), OnCryptographerStateChanged(_)).Times(AnyNumber()); |
- EXPECT_CALL(*observer(), OnEncryptedTypesChanged( |
- HasModelTypes(EncryptableUserTypes()), true)); |
- { |
- // Update the encryption handler. |
- WriteTransaction trans(FROM_HERE, user_share()); |
- encryption_handler()->ApplyNigoriUpdate( |
- current_nigori_specifics, |
- trans.GetWrappedTrans()); |
- } |
- Mock::VerifyAndClearExpectations(observer()); |
- |
- // 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_encryption_keybag()); |
- |
- EXPECT_CALL(*observer(), OnCryptographerStateChanged(_)).Times(AnyNumber()); |
- { |
- // Update the encryption handler. |
- WriteTransaction trans(FROM_HERE, user_share()); |
- encryption_handler()->ApplyNigoriUpdate( |
- old_nigori, |
- trans.GetWrappedTrans()); |
- } |
- EXPECT_TRUE(GetCryptographer()->is_ready()); |
- EXPECT_FALSE(GetCryptographer()->has_pending_keys()); |
- |
- // Encryption handler should have posted a task to overwrite the old |
- // specifics. |
- PumpLoop(); |
- |
- { |
- // The cryptographer should be able to decrypt both sets of keys and still |
- // be encrypting with the newest, and the encrypted types should be the |
- // most recent. |
- // 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.InitTypeRoot(NIGORI), 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.encryption_keybag())); |
- EXPECT_TRUE(nigori.encrypt_everything()); |
- EXPECT_TRUE( |
- GetCryptographer()->CanDecryptUsingDefaultKey( |
- nigori.encryption_keybag())); |
- } |
- EXPECT_TRUE(encryption_handler()->IsEncryptEverythingEnabled()); |
-} |
- |
-// Ensure setting the keystore key works, updates the bootstrap token, and |
-// triggers a non-backwards compatible migration. Then verify that the |
-// bootstrap token can be correctly parsed by the encryption handler at startup |
-// time. |
-TEST_F(SyncEncryptionHandlerImplTest, SetKeystoreMigratesAndUpdatesBootstrap) { |
- // Passing no keys should do nothing. |
- EXPECT_CALL(*observer(), OnBootstrapTokenUpdated(_, _)).Times(0); |
- { |
- WriteTransaction trans(FROM_HERE, user_share()); |
- EXPECT_FALSE(GetCryptographer()->is_initialized()); |
- EXPECT_TRUE(encryption_handler()->NeedKeystoreKey(trans.GetWrappedTrans())); |
- EXPECT_FALSE(encryption_handler()->SetKeystoreKeys( |
- BuildEncryptionKeyProto(std::string()), trans.GetWrappedTrans())); |
- EXPECT_TRUE(encryption_handler()->NeedKeystoreKey(trans.GetWrappedTrans())); |
- } |
- Mock::VerifyAndClearExpectations(observer()); |
- |
- // Build a set of keystore keys. |
- const char kRawOldKeystoreKey[] = "old_keystore_key"; |
- std::string old_keystore_key; |
- base::Base64Encode(kRawOldKeystoreKey, &old_keystore_key); |
- google::protobuf::RepeatedPtrField<google::protobuf::string> keys; |
- keys.Add()->assign(kRawOldKeystoreKey); |
- keys.Add()->assign(kRawKeystoreKey); |
- |
- // Pass them to the encryption handler, triggering a migration and bootstrap |
- // token update. |
- std::string encoded_key; |
- std::string keystore_bootstrap; |
- EXPECT_CALL(*observer(), OnEncryptionComplete()); |
- EXPECT_CALL(*observer(), OnCryptographerStateChanged(_)); |
- EXPECT_CALL(*observer(), OnPassphraseAccepted()); |
- EXPECT_CALL(*observer(), OnPassphraseTypeChanged(KEYSTORE_PASSPHRASE, _)); |
- EXPECT_CALL(*observer(), |
- OnBootstrapTokenUpdated(_, |
- KEYSTORE_BOOTSTRAP_TOKEN)). |
- WillOnce(SaveArg<0>(&keystore_bootstrap)); |
- { |
- WriteTransaction trans(FROM_HERE, user_share()); |
- EXPECT_TRUE( |
- encryption_handler()->SetKeystoreKeys( |
- keys, |
- trans.GetWrappedTrans())); |
- EXPECT_FALSE( |
- encryption_handler()->NeedKeystoreKey(trans.GetWrappedTrans())); |
- EXPECT_FALSE(GetCryptographer()->is_initialized()); |
- } |
- PumpLoop(); |
- EXPECT_TRUE(GetCryptographer()->is_initialized()); |
- VerifyMigratedNigori(KEYSTORE_PASSPHRASE, kKeystoreKey); |
- |
- // Ensure the bootstrap is encoded properly (a base64 encoded encrypted blob |
- // of list values containing the keystore keys). |
- std::string decoded_bootstrap; |
- ASSERT_TRUE(base::Base64Decode(keystore_bootstrap, &decoded_bootstrap)); |
- std::string decrypted_bootstrap; |
- ASSERT_TRUE( |
- GetCryptographer()->encryptor()->DecryptString(decoded_bootstrap, |
- &decrypted_bootstrap)); |
- JSONStringValueDeserializer json(decrypted_bootstrap); |
- std::unique_ptr<base::Value> deserialized_keystore_keys( |
- json.Deserialize(NULL, NULL)); |
- ASSERT_TRUE(deserialized_keystore_keys.get()); |
- base::ListValue* keystore_list = NULL; |
- deserialized_keystore_keys->GetAsList(&keystore_list); |
- ASSERT_TRUE(keystore_list); |
- ASSERT_EQ(2U, keystore_list->GetSize()); |
- std::string test_string; |
- keystore_list->GetString(0, &test_string); |
- ASSERT_EQ(old_keystore_key, test_string); |
- keystore_list->GetString(1, &test_string); |
- ASSERT_EQ(kKeystoreKey, test_string); |
- |
- |
- // Now make sure a new encryption handler can correctly parse the bootstrap |
- // token. |
- SyncEncryptionHandlerImpl handler2(user_share(), &encryptor_, |
- std::string(), // Cryptographer bootstrap. |
- keystore_bootstrap); |
- |
- { |
- WriteTransaction trans(FROM_HERE, user_share()); |
- EXPECT_FALSE(handler2.NeedKeystoreKey(trans.GetWrappedTrans())); |
- } |
-} |
- |
-// 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()->SetKeystoreKeys(BuildEncryptionKeyProto( |
- kRawKeystoreKey), |
- trans.GetWrappedTrans()); |
- Mock::VerifyAndClearExpectations(observer()); |
- } |
- EXPECT_FALSE(encryption_handler()->MigratedToKeystore()); |
- |
- { |
- WriteTransaction trans(FROM_HERE, user_share()); |
- WriteNode nigori_node(&trans); |
- ASSERT_EQ(nigori_node.InitTypeRoot(NIGORI), 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(_)).Times(AnyNumber()); |
- 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(_)).Times(AnyNumber()); |
- 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()->SetKeystoreKeys(BuildEncryptionKeyProto( |
- kRawKeystoreKey), |
- trans.GetWrappedTrans()); |
- Mock::VerifyAndClearExpectations(observer()); |
- } |
- EXPECT_FALSE(encryption_handler()->MigratedToKeystore()); |
- |
- { |
- WriteTransaction trans(FROM_HERE, user_share()); |
- WriteNode nigori_node(&trans); |
- ASSERT_EQ(nigori_node.InitTypeRoot(NIGORI), 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(_)).Times(AnyNumber()); |
- 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(_)).Times(AnyNumber()); |
- EXPECT_CALL(*observer(), |
- OnPassphraseAccepted()); |
- std::string captured_bootstrap_token; |
- EXPECT_CALL(*observer(), |
- OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)) |
- .WillOnce(testing::SaveArg<0>(&captured_bootstrap_token)); |
- EXPECT_CALL(*observer(), |
- OnEncryptedTypesChanged(_, true)); |
- SyncEncryptionHandler::NigoriState captured_nigori_state; |
- EXPECT_CALL(*observer(), OnLocalSetPassphraseEncryption(_)) |
- .WillOnce(testing::SaveArg<0>(&captured_nigori_state)); |
- EXPECT_CALL(*observer(), |
- OnEncryptionComplete()).Times(2); |
- EXPECT_FALSE(encryption_handler()->MigratedToKeystore()); |
- encryption_handler()->SetDecryptionPassphrase(kOtherKey); |
- EXPECT_TRUE(encryption_handler()->MigratedToKeystore()); |
- const base::Time migration_time = encryption_handler()->migration_time(); |
- EXPECT_EQ(CUSTOM_PASSPHRASE, encryption_handler()->GetPassphraseType()); |
- VerifyMigratedNigori(CUSTOM_PASSPHRASE, kOtherKey); |
- |
- VerifyRestoreAfterCustomPassphrase(TimeToProtoTime(migration_time), kOtherKey, |
- captured_bootstrap_token, |
- captured_nigori_state, CUSTOM_PASSPHRASE); |
-} |
- |
-// 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(_)).Times(AnyNumber()); |
- 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(), |
- OnCryptographerStateChanged(_)).Times(AnyNumber()); |
- EXPECT_CALL(*observer(), |
- OnBootstrapTokenUpdated(_, KEYSTORE_BOOTSTRAP_TOKEN)); |
- encryption_handler()->SetKeystoreKeys(BuildEncryptionKeyProto( |
- kRawKeystoreKey), |
- 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()->IsEncryptEverythingEnabled()); |
- 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(_)).Times(AnyNumber()); |
- EXPECT_CALL(*observer(), |
- OnEncryptedTypesChanged(_, false)); |
- EXPECT_CALL(*observer(), |
- OnEncryptionComplete()); |
- encryption_handler()->Init(); |
- Mock::VerifyAndClearExpectations(observer()); |
- EXPECT_CALL(*observer(), |
- OnEncryptedTypesChanged(_, true)); |
- SyncEncryptionHandler::NigoriState captured_nigori_state; |
- EXPECT_CALL(*observer(), OnLocalSetPassphraseEncryption(_)) |
- .WillOnce(testing::SaveArg<0>(&captured_nigori_state)); |
- 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(), |
- OnCryptographerStateChanged(_)).Times(AnyNumber()); |
- EXPECT_CALL(*observer(), |
- OnBootstrapTokenUpdated(_, KEYSTORE_BOOTSTRAP_TOKEN)); |
- encryption_handler()->SetKeystoreKeys(BuildEncryptionKeyProto( |
- kRawKeystoreKey), |
- trans.GetWrappedTrans()); |
- } |
- EXPECT_CALL(*observer(), |
- OnPassphraseTypeChanged(FROZEN_IMPLICIT_PASSPHRASE, _)); |
- |
- // The actual migration gets posted, so run all pending tasks. |
- PumpLoop(); |
- Mock::VerifyAndClearExpectations(observer()); |
- |
- EXPECT_TRUE(encryption_handler()->MigratedToKeystore()); |
- const base::Time migration_time = encryption_handler()->migration_time(); |
- EXPECT_EQ(FROZEN_IMPLICIT_PASSPHRASE, |
- encryption_handler()->GetPassphraseType()); |
- EXPECT_TRUE(encryption_handler()->IsEncryptEverythingEnabled()); |
- VerifyMigratedNigori(FROZEN_IMPLICIT_PASSPHRASE, kCurKey); |
- |
- // We need the passphrase bootstrap token, but OnBootstrapTokenUpdated(_, |
- // PASSPHRASE_BOOTSTRAP_TOKEN) has not been invoked (because it was invoked |
- // during a previous instance) so get it from the Cryptographer. |
- std::string passphrase_bootstrap_token; |
- GetCryptographer()->GetBootstrapToken(&passphrase_bootstrap_token); |
- VerifyRestoreAfterCustomPassphrase( |
- TimeToProtoTime(migration_time), kCurKey, passphrase_bootstrap_token, |
- captured_nigori_state, FROZEN_IMPLICIT_PASSPHRASE); |
-} |
- |
-// 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(AnyNumber()); |
- EXPECT_CALL(*observer(), |
- OnPassphraseRequired(_, _)); |
- EXPECT_CALL(*observer(), |
- OnPassphraseAccepted()); |
- EXPECT_CALL(*observer(), |
- OnEncryptedTypesChanged(_, false)); |
- EXPECT_CALL(*observer(), |
- OnEncryptionComplete()); |
- EXPECT_CALL(*observer(), |
- OnPassphraseTypeChanged(CUSTOM_PASSPHRASE, _)); |
- std::string captured_bootstrap_token; |
- EXPECT_CALL(*observer(), |
- OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)) |
- .WillOnce(testing::SaveArg<0>(&captured_bootstrap_token)); |
- encryption_handler()->Init(); |
- encryption_handler()->SetEncryptionPassphrase(kCurKey, true); |
- EXPECT_FALSE(encryption_handler()->custom_passphrase_time().is_null()); |
- Mock::VerifyAndClearExpectations(observer()); |
- |
- EXPECT_CALL(*observer(), |
- OnEncryptedTypesChanged(_, true)); |
- EXPECT_CALL(*observer(), |
- OnEncryptionComplete()); |
- encryption_handler()->EnableEncryptEverything(); |
- Mock::VerifyAndClearExpectations(observer()); |
- |
- SyncEncryptionHandler::NigoriState captured_nigori_state; |
- { |
- ReadTransaction trans(FROM_HERE, user_share()); |
- // Once we provide a keystore key, we should perform the migration. |
- EXPECT_CALL(*observer(), |
- OnCryptographerStateChanged(_)).Times(AnyNumber()); |
- EXPECT_CALL(*observer(), |
- OnBootstrapTokenUpdated(_, KEYSTORE_BOOTSTRAP_TOKEN)); |
- EXPECT_CALL(*observer(), OnLocalSetPassphraseEncryption(_)) |
- .WillOnce(testing::SaveArg<0>(&captured_nigori_state)); |
- encryption_handler()->SetKeystoreKeys(BuildEncryptionKeyProto( |
- kRawKeystoreKey), |
- trans.GetWrappedTrans()); |
- } |
- |
- // The actual migration gets posted, so run all pending tasks. |
- PumpLoop(); |
- Mock::VerifyAndClearExpectations(observer()); |
- |
- EXPECT_TRUE(encryption_handler()->MigratedToKeystore()); |
- const base::Time migration_time = encryption_handler()->migration_time(); |
- EXPECT_EQ(CUSTOM_PASSPHRASE, |
- encryption_handler()->GetPassphraseType()); |
- EXPECT_TRUE(encryption_handler()->IsEncryptEverythingEnabled()); |
- VerifyMigratedNigori(CUSTOM_PASSPHRASE, kCurKey); |
- |
- VerifyRestoreAfterCustomPassphrase(TimeToProtoTime(migration_time), kCurKey, |
- captured_bootstrap_token, |
- captured_nigori_state, CUSTOM_PASSPHRASE); |
-} |
- |
-// 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(AnyNumber()); |
- EXPECT_CALL(*observer(), |
- OnPassphraseRequired(_, _)); |
- EXPECT_CALL(*observer(), |
- OnPassphraseAccepted()); |
- EXPECT_CALL(*observer(), |
- OnEncryptedTypesChanged(_, false)); |
- EXPECT_CALL(*observer(), |
- OnEncryptionComplete()); |
- EXPECT_CALL(*observer(), |
- OnPassphraseTypeChanged(CUSTOM_PASSPHRASE, _)); |
- std::string captured_bootstrap_token; |
- EXPECT_CALL(*observer(), |
- OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)) |
- .WillOnce(testing::SaveArg<0>(&captured_bootstrap_token)); |
- encryption_handler()->Init(); |
- encryption_handler()->SetEncryptionPassphrase(kCurKey, true); |
- EXPECT_FALSE(encryption_handler()->custom_passphrase_time().is_null()); |
- Mock::VerifyAndClearExpectations(observer()); |
- |
- { |
- ReadTransaction trans(FROM_HERE, user_share()); |
- // Once we provide a keystore key, we should perform the migration. |
- EXPECT_CALL(*observer(), |
- OnCryptographerStateChanged(_)).Times(AnyNumber()); |
- EXPECT_CALL(*observer(), |
- OnBootstrapTokenUpdated(_, KEYSTORE_BOOTSTRAP_TOKEN)); |
- encryption_handler()->SetKeystoreKeys(BuildEncryptionKeyProto( |
- kRawKeystoreKey), |
- trans.GetWrappedTrans()); |
- } |
- EXPECT_CALL(*observer(), |
- OnEncryptedTypesChanged(_, true)); |
- SyncEncryptionHandler::NigoriState captured_nigori_state; |
- EXPECT_CALL(*observer(), OnLocalSetPassphraseEncryption(_)) |
- .WillOnce(testing::SaveArg<0>(&captured_nigori_state)); |
- EXPECT_CALL(*observer(), |
- OnEncryptionComplete()); |
- // The actual migration gets posted, so run all pending tasks. |
- PumpLoop(); |
- EXPECT_TRUE(encryption_handler()->MigratedToKeystore()); |
- const base::Time migration_time = encryption_handler()->migration_time(); |
- EXPECT_EQ(CUSTOM_PASSPHRASE, |
- encryption_handler()->GetPassphraseType()); |
- EXPECT_TRUE(encryption_handler()->IsEncryptEverythingEnabled()); |
- VerifyMigratedNigori(CUSTOM_PASSPHRASE, kCurKey); |
- |
- VerifyRestoreAfterCustomPassphrase(TimeToProtoTime(migration_time), kCurKey, |
- captured_bootstrap_token, |
- captured_nigori_state, CUSTOM_PASSPHRASE); |
-} |
- |
-// 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.InitTypeRoot(NIGORI), 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(), OnPassphraseAccepted()); |
- 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(AnyNumber()); |
- encryption_handler()->SetKeystoreKeys(BuildEncryptionKeyProto( |
- kRawKeystoreKey), |
- 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()->IsEncryptEverythingEnabled()); |
- 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()->SetKeystoreKeys(BuildEncryptionKeyProto( |
- kRawKeystoreKey), |
- trans.GetWrappedTrans()); |
- } |
- EXPECT_FALSE(encryption_handler()->MigratedToKeystore()); |
- |
- { |
- EXPECT_CALL(*observer(), |
- OnPassphraseTypeChanged(FROZEN_IMPLICIT_PASSPHRASE, _)); |
- EXPECT_CALL(*observer(), |
- OnPassphraseRequired(_, _)); |
- EXPECT_CALL(*observer(), |
- OnCryptographerStateChanged(_)).Times(AnyNumber()); |
- EXPECT_CALL(*observer(), |
- OnEncryptedTypesChanged(_, true)); |
- WriteTransaction trans(FROM_HERE, user_share()); |
- WriteNode nigori_node(&trans); |
- ASSERT_EQ(nigori_node.InitTypeRoot(NIGORI), 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()->IsEncryptEverythingEnabled()); |
- |
- EXPECT_CALL(*observer(), |
- OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)); |
- EXPECT_CALL(*observer(), |
- OnCryptographerStateChanged(_)).Times(AnyNumber()); |
- 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 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()->SetKeystoreKeys(BuildEncryptionKeyProto( |
- kRawKeystoreKey), |
- trans.GetWrappedTrans()); |
- } |
- EXPECT_FALSE(encryption_handler()->MigratedToKeystore()); |
- |
- { |
- EXPECT_CALL(*observer(), |
- OnPassphraseTypeChanged(CUSTOM_PASSPHRASE, _)); |
- EXPECT_CALL(*observer(), |
- OnPassphraseRequired(_, _)); |
- EXPECT_CALL(*observer(), |
- OnCryptographerStateChanged(_)).Times(AnyNumber()); |
- EXPECT_CALL(*observer(), |
- OnEncryptedTypesChanged(_, true)); |
- WriteTransaction trans(FROM_HERE, user_share()); |
- WriteNode nigori_node(&trans); |
- ASSERT_EQ(nigori_node.InitTypeRoot(NIGORI), 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()->IsEncryptEverythingEnabled()); |
- |
- EXPECT_CALL(*observer(), |
- OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)); |
- EXPECT_CALL(*observer(), |
- OnCryptographerStateChanged(_)).Times(AnyNumber()); |
- 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. |
- const int64_t migration_time = 1; |
- { |
- WriteTransaction trans(FROM_HERE, user_share()); |
- WriteNode nigori_node(&trans); |
- ASSERT_EQ(nigori_node.InitTypeRoot(NIGORI), 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(_)).Times(AnyNumber()); |
- 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()->IsEncryptEverythingEnabled()); |
- VerifyMigratedNigoriWithTimestamp(migration_time, CUSTOM_PASSPHRASE, kCurKey); |
- |
- { |
- EXPECT_CALL(*observer(), |
- OnBootstrapTokenUpdated(_, KEYSTORE_BOOTSTRAP_TOKEN)); |
- ReadTransaction trans(FROM_HERE, user_share()); |
- encryption_handler()->SetKeystoreKeys(BuildEncryptionKeyProto( |
- kRawKeystoreKey), |
- 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(_)).Times(AnyNumber()); |
- SyncEncryptionHandler::NigoriState captured_nigori_state; |
- EXPECT_CALL(*observer(), OnLocalSetPassphraseEncryption(_)) |
- .WillOnce(testing::SaveArg<0>(&captured_nigori_state)); |
- EXPECT_CALL(*observer(), OnEncryptionComplete()); |
- { |
- Cryptographer other_cryptographer(GetCryptographer()->encryptor()); |
- other_cryptographer.AddKey(old_key); |
- WriteTransaction trans(FROM_HERE, user_share()); |
- WriteNode nigori_node(&trans); |
- ASSERT_EQ(nigori_node.InitTypeRoot(NIGORI), 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()->IsEncryptEverythingEnabled()); |
- VerifyMigratedNigoriWithTimestamp(1, CUSTOM_PASSPHRASE, kCurKey); |
- |
- // We need the passphrase bootstrap token, but OnBootstrapTokenUpdated(_, |
- // PASSPHRASE_BOOTSTRAP_TOKEN) has not been invoked (because it was invoked |
- // during a previous instance) so get it from the Cryptographer. |
- std::string passphrase_bootstrap_token; |
- GetCryptographer()->GetBootstrapToken(&passphrase_bootstrap_token); |
- VerifyRestoreAfterCustomPassphrase(migration_time, kCurKey, |
- passphrase_bootstrap_token, |
- captured_nigori_state, CUSTOM_PASSPHRASE); |
-} |
- |
-// 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}; |
- 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.InitTypeRoot(NIGORI), 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(_)).Times(AnyNumber()); |
- 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()->IsEncryptEverythingEnabled()); |
- VerifyMigratedNigoriWithTimestamp(1, CUSTOM_PASSPHRASE, kCurKey); |
- |
- { |
- EXPECT_CALL(*observer(), |
- OnBootstrapTokenUpdated(_, KEYSTORE_BOOTSTRAP_TOKEN)); |
- ReadTransaction trans(FROM_HERE, user_share()); |
- encryption_handler()->SetKeystoreKeys(BuildEncryptionKeyProto( |
- kRawKeystoreKey), |
- 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(_)).Times(AnyNumber()); |
- SyncEncryptionHandler::NigoriState captured_nigori_state; |
- EXPECT_CALL(*observer(), OnLocalSetPassphraseEncryption(_)) |
- .WillOnce(testing::SaveArg<0>(&captured_nigori_state)); |
- EXPECT_CALL(*observer(), OnEncryptionComplete()); |
- const int64_t migration_time = 1; |
- { |
- WriteTransaction trans(FROM_HERE, user_share()); |
- WriteNode nigori_node(&trans); |
- ASSERT_EQ(nigori_node.InitTypeRoot(NIGORI), 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(migration_time); |
- 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()->IsEncryptEverythingEnabled()); |
- VerifyMigratedNigoriWithTimestamp(migration_time, CUSTOM_PASSPHRASE, kCurKey); |
- |
- // We need the passphrase bootstrap token, but OnBootstrapTokenUpdated(_, |
- // PASSPHRASE_BOOTSTRAP_TOKEN) has not been invoked (because it was invoked |
- // during a previous instance) so get it from the Cryptographer. |
- std::string passphrase_bootstrap_token; |
- GetCryptographer()->GetBootstrapToken(&passphrase_bootstrap_token); |
- VerifyRestoreAfterCustomPassphrase(migration_time, kCurKey, |
- passphrase_bootstrap_token, |
- captured_nigori_state, CUSTOM_PASSPHRASE); |
-} |
- |
-// 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.InitTypeRoot(NIGORI), 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(_)).Times(AnyNumber()); |
- 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()->IsEncryptEverythingEnabled()); |
- Mock::VerifyAndClearExpectations(observer()); |
- |
- EXPECT_CALL(*observer(), OnPassphraseAccepted()); |
- EXPECT_CALL(*observer(), |
- OnCryptographerStateChanged(_)).Times(AnyNumber()); |
- EXPECT_CALL(*observer(), |
- OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)); |
- { |
- EXPECT_CALL(*observer(), |
- OnBootstrapTokenUpdated(_, KEYSTORE_BOOTSTRAP_TOKEN)); |
- ReadTransaction trans(FROM_HERE, user_share()); |
- encryption_handler()->SetKeystoreKeys(BuildEncryptionKeyProto( |
- kRawKeystoreKey), |
- trans.GetWrappedTrans()); |
- } |
- PumpLoop(); |
- EXPECT_TRUE(encryption_handler()->MigratedToKeystore()); |
- EXPECT_TRUE(GetCryptographer()->is_ready()); |
- EXPECT_EQ(encryption_handler()->GetPassphraseType(), KEYSTORE_PASSPHRASE); |
- EXPECT_FALSE(encryption_handler()->IsEncryptEverythingEnabled()); |
- 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. |
- const int64_t migration_time = 1; |
- { |
- WriteTransaction trans(FROM_HERE, user_share()); |
- WriteNode nigori_node(&trans); |
- ASSERT_EQ(nigori_node.InitTypeRoot(NIGORI), 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(migration_time); |
- nigori.set_passphrase_type(sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE); |
- nigori_node.SetNigoriSpecifics(nigori); |
- EXPECT_CALL(*observer(), |
- OnBootstrapTokenUpdated(_, KEYSTORE_BOOTSTRAP_TOKEN)); |
- encryption_handler()->SetKeystoreKeys(BuildEncryptionKeyProto( |
- kRawKeystoreKey), |
- trans.GetWrappedTrans()); |
- } |
- |
- EXPECT_CALL(*observer(), OnPassphraseAccepted()); |
- EXPECT_CALL(*observer(), |
- OnPassphraseTypeChanged(KEYSTORE_PASSPHRASE, _)); |
- EXPECT_CALL(*observer(), |
- OnCryptographerStateChanged(_)).Times(AnyNumber()); |
- 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()->IsEncryptEverythingEnabled()); |
- Mock::VerifyAndClearExpectations(observer()); |
- |
- const char kNewKey[] = "new_key"; |
- EXPECT_CALL(*observer(), |
- OnCryptographerStateChanged(_)).Times(AnyNumber()); |
- EXPECT_CALL(*observer(), |
- OnPassphraseTypeChanged(CUSTOM_PASSPHRASE, _)); |
- SyncEncryptionHandler::NigoriState captured_nigori_state; |
- EXPECT_CALL(*observer(), OnLocalSetPassphraseEncryption(_)) |
- .WillOnce(testing::SaveArg<0>(&captured_nigori_state)); |
- std::string captured_bootstrap_token; |
- EXPECT_CALL(*observer(), |
- OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)) |
- .WillOnce(testing::SaveArg<0>(&captured_bootstrap_token)); |
- EXPECT_CALL(*observer(), |
- OnPassphraseAccepted()); |
- EXPECT_CALL(*observer(), |
- OnEncryptedTypesChanged(_, true)); |
- EXPECT_CALL(*observer(), |
- OnEncryptionComplete()).Times(2); |
- encryption_handler()->SetEncryptionPassphrase(kNewKey, true); |
- Mock::VerifyAndClearExpectations(observer()); |
- |
- EXPECT_FALSE(captured_bootstrap_token.empty()); |
- EXPECT_TRUE(encryption_handler()->MigratedToKeystore()); |
- EXPECT_TRUE(GetCryptographer()->is_ready()); |
- EXPECT_EQ(encryption_handler()->GetPassphraseType(), CUSTOM_PASSPHRASE); |
- EXPECT_TRUE(encryption_handler()->IsEncryptEverythingEnabled()); |
- EXPECT_FALSE(encryption_handler()->custom_passphrase_time().is_null()); |
- VerifyMigratedNigoriWithTimestamp(migration_time, 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)); |
- |
- // Now verify that we can restore the current state using the captured |
- // bootstrap token and nigori state. |
- VerifyRestoreAfterCustomPassphrase(migration_time, kNewKey, |
- captured_bootstrap_token, |
- captured_nigori_state, CUSTOM_PASSPHRASE); |
-} |
- |
-// 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. |
- const int64_t migration_time = 1; |
- { |
- WriteTransaction trans(FROM_HERE, user_share()); |
- WriteNode nigori_node(&trans); |
- ASSERT_EQ(nigori_node.InitTypeRoot(NIGORI), 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(migration_time); |
- 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(_)).Times(AnyNumber()); |
- 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()->IsEncryptEverythingEnabled()); |
- Mock::VerifyAndClearExpectations(observer()); |
- |
- EXPECT_CALL(*observer(), |
- OnPassphraseAccepted()); |
- EXPECT_CALL(*observer(), |
- OnCryptographerStateChanged(_)).Times(AnyNumber()); |
- EXPECT_CALL(*observer(), |
- OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)); |
- EXPECT_CALL(*observer(), |
- OnEncryptionComplete()); |
- encryption_handler()->SetDecryptionPassphrase(kOldKey); |
- EXPECT_TRUE(GetCryptographer()->is_ready()); |
- EXPECT_FALSE(encryption_handler()->IsEncryptEverythingEnabled()); |
- Mock::VerifyAndClearExpectations(observer()); |
- |
- const char kNewKey[] = "new_key"; |
- EXPECT_CALL(*observer(), |
- OnCryptographerStateChanged(_)).Times(AnyNumber()); |
- EXPECT_CALL(*observer(), |
- OnPassphraseTypeChanged(CUSTOM_PASSPHRASE, _)); |
- SyncEncryptionHandler::NigoriState captured_nigori_state; |
- EXPECT_CALL(*observer(), OnLocalSetPassphraseEncryption(_)) |
- .WillOnce(testing::SaveArg<0>(&captured_nigori_state)); |
- std::string captured_bootstrap_token; |
- EXPECT_CALL(*observer(), |
- OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)) |
- .WillOnce(testing::SaveArg<0>(&captured_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()->IsEncryptEverythingEnabled()); |
- EXPECT_FALSE(encryption_handler()->custom_passphrase_time().is_null()); |
- VerifyMigratedNigoriWithTimestamp(migration_time, 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)); |
- |
- // Now verify that we can restore the current state using the captured |
- // bootstrap token and nigori state. |
- VerifyRestoreAfterCustomPassphrase(migration_time, kNewKey, |
- captured_bootstrap_token, |
- captured_nigori_state, CUSTOM_PASSPHRASE); |
-} |
- |
-// 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.InitTypeRoot(NIGORI), 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(_)).Times(AnyNumber()); |
- 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()->IsEncryptEverythingEnabled()); |
- Mock::VerifyAndClearExpectations(observer()); |
- |
- EXPECT_CALL(*observer(), |
- OnPassphraseAccepted()); |
- EXPECT_CALL(*observer(), |
- OnCryptographerStateChanged(_)).Times(AnyNumber()); |
- EXPECT_CALL(*observer(), |
- OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)); |
- EXPECT_CALL(*observer(), |
- OnEncryptionComplete()); |
- encryption_handler()->SetDecryptionPassphrase(kOldKey); |
- EXPECT_TRUE(GetCryptographer()->is_ready()); |
- EXPECT_FALSE(encryption_handler()->IsEncryptEverythingEnabled()); |
- 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()->IsEncryptEverythingEnabled()); |
- 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. |
- const int64_t migration_time = 1; |
- { |
- WriteTransaction trans(FROM_HERE, user_share()); |
- WriteNode nigori_node(&trans); |
- ASSERT_EQ(nigori_node.InitTypeRoot(NIGORI), 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(migration_time); |
- 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(_)).Times(AnyNumber()); |
- 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()->IsEncryptEverythingEnabled()); |
- Mock::VerifyAndClearExpectations(observer()); |
- |
- EXPECT_CALL(*observer(), |
- OnPassphraseAccepted()); |
- EXPECT_CALL(*observer(), |
- OnCryptographerStateChanged(_)).Times(AnyNumber()); |
- std::string captured_bootstrap_token; |
- EXPECT_CALL(*observer(), |
- OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)) |
- .WillOnce(testing::SaveArg<0>(&captured_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)); |
- SyncEncryptionHandler::NigoriState captured_nigori_state; |
- EXPECT_CALL(*observer(), OnLocalSetPassphraseEncryption(_)) |
- .WillOnce(testing::SaveArg<0>(&captured_nigori_state)); |
- EXPECT_CALL(*observer(), |
- OnCryptographerStateChanged(_)).Times(AnyNumber()); |
- 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()->IsEncryptEverythingEnabled()); |
- 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)); |
- |
- VerifyRestoreAfterCustomPassphrase( |
- migration_time, kCurKey, captured_bootstrap_token, captured_nigori_state, |
- FROZEN_IMPLICIT_PASSPHRASE); |
-} |
- |
-// If we receive a nigori migrated and with a KEYSTORE_PASSPHRASE type, but |
-// using an old default key (i.e. old GAIA password), we should overwrite the |
-// nigori, updating the keybag and keystore decryptor. |
-TEST_F(SyncEncryptionHandlerImplTest, |
- ReceiveMigratedNigoriWithOldPassphrase) { |
- 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); |
- |
- Cryptographer other_cryptographer(GetCryptographer()->encryptor()); |
- other_cryptographer.AddKey(old_key); |
- EXPECT_TRUE(other_cryptographer.is_ready()); |
- |
- EXPECT_CALL(*observer(), |
- OnCryptographerStateChanged(_)).Times(AnyNumber()); |
- EXPECT_CALL(*observer(), |
- OnEncryptedTypesChanged(_, false)); |
- EXPECT_CALL(*observer(), |
- OnEncryptionComplete()); |
- encryption_handler()->Init(); |
- EXPECT_TRUE(GetCryptographer()->is_ready()); |
- EXPECT_FALSE(encryption_handler()->IsEncryptEverythingEnabled()); |
- |
- { |
- EXPECT_CALL(*observer(), |
- OnBootstrapTokenUpdated(_, KEYSTORE_BOOTSTRAP_TOKEN)); |
- ReadTransaction trans(FROM_HERE, user_share()); |
- encryption_handler()->SetKeystoreKeys(BuildEncryptionKeyProto( |
- kRawKeystoreKey), |
- trans.GetWrappedTrans()); |
- } |
- EXPECT_CALL(*observer(), |
- OnPassphraseTypeChanged(KEYSTORE_PASSPHRASE, _)); |
- PumpLoop(); |
- Mock::VerifyAndClearExpectations(observer()); |
- EXPECT_TRUE(encryption_handler()->MigratedToKeystore()); |
- EXPECT_EQ(encryption_handler()->GetPassphraseType(), KEYSTORE_PASSPHRASE); |
- VerifyMigratedNigori(KEYSTORE_PASSPHRASE, kCurKey); |
- |
- // Now build an old keystore passphrase nigori node. |
- EXPECT_CALL(*observer(), |
- OnCryptographerStateChanged(_)).Times(AnyNumber()); |
- EXPECT_CALL(*observer(), OnEncryptionComplete()); |
- { |
- WriteTransaction trans(FROM_HERE, user_share()); |
- WriteNode nigori_node(&trans); |
- ASSERT_EQ(nigori_node.InitTypeRoot(NIGORI), 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(), KEYSTORE_PASSPHRASE); |
- EXPECT_FALSE(encryption_handler()->IsEncryptEverythingEnabled()); |
- VerifyMigratedNigori(KEYSTORE_PASSPHRASE, kCurKey); |
-} |
- |
-// Trigger a key rotation upon receiving new keys if we already had a keystore |
-// migrated nigori with the gaia key as the default (still in backwards |
-// compatible mode). |
-TEST_F(SyncEncryptionHandlerImplTest, RotateKeysGaiaDefault) { |
- // Destroy the existing nigori node so we init without a nigori node. |
- TearDown(); |
- test_user_share_.SetUp(); |
- SetUpEncryption(); |
- |
- const char kOldGaiaKey[] = "old_gaia_key"; |
- const char kRawOldKeystoreKey[] = "old_keystore_key"; |
- std::string old_keystore_key; |
- base::Base64Encode(kRawOldKeystoreKey, &old_keystore_key); |
- { |
- ReadTransaction trans(FROM_HERE, user_share()); |
- EXPECT_CALL(*observer(), |
- OnBootstrapTokenUpdated(_, KEYSTORE_BOOTSTRAP_TOKEN)); |
- encryption_handler()->SetKeystoreKeys(BuildEncryptionKeyProto( |
- kRawOldKeystoreKey), |
- trans.GetWrappedTrans()); |
- } |
- PumpLoop(); |
- Mock::VerifyAndClearExpectations(observer()); |
- |
- // Then init the nigori node with a backwards compatible set of keys. |
- CreateRootForType(NIGORI); |
- EXPECT_CALL(*observer(), OnPassphraseAccepted()); |
- InitKeystoreMigratedNigori(1, kOldGaiaKey, old_keystore_key); |
- |
- // Now set some new keystore keys. |
- EXPECT_CALL(*observer(), OnCryptographerStateChanged(_)).Times(AnyNumber()); |
- EXPECT_CALL(*observer(), OnEncryptionComplete()); |
- { |
- google::protobuf::RepeatedPtrField<google::protobuf::string> keys; |
- keys.Add()->assign(kRawOldKeystoreKey); |
- keys.Add()->assign(kRawKeystoreKey); |
- EXPECT_CALL(*observer(), |
- OnBootstrapTokenUpdated(_, KEYSTORE_BOOTSTRAP_TOKEN)); |
- ReadTransaction trans(FROM_HERE, user_share()); |
- encryption_handler()->SetKeystoreKeys(keys, |
- trans.GetWrappedTrans()); |
- } |
- // Pump for any posted tasks. |
- PumpLoop(); |
- Mock::VerifyAndClearExpectations(observer()); |
- |
- // Verify we're still migrated and have proper encryption state. We should |
- // have rotated the keybag so that it's now encrypted with the newest keystore |
- // key (instead of the old gaia key). |
- EXPECT_TRUE(encryption_handler()->MigratedToKeystore()); |
- EXPECT_TRUE(GetCryptographer()->is_ready()); |
- EXPECT_EQ(encryption_handler()->GetPassphraseType(), KEYSTORE_PASSPHRASE); |
- EXPECT_FALSE(encryption_handler()->IsEncryptEverythingEnabled()); |
- VerifyMigratedNigori(KEYSTORE_PASSPHRASE, kKeystoreKey); |
-} |
- |
-// Trigger a key rotation upon receiving new keys if we already had a keystore |
-// migrated nigori with the keystore key as the default. |
-TEST_F(SyncEncryptionHandlerImplTest, RotateKeysKeystoreDefault) { |
- // Destroy the existing nigori node so we init without a nigori node. |
- TearDown(); |
- test_user_share_.SetUp(); |
- SetUpEncryption(); |
- |
- const char kRawOldKeystoreKey[] = "old_keystore_key"; |
- std::string old_keystore_key; |
- base::Base64Encode(kRawOldKeystoreKey, &old_keystore_key); |
- { |
- ReadTransaction trans(FROM_HERE, user_share()); |
- EXPECT_CALL(*observer(), |
- OnBootstrapTokenUpdated(_, KEYSTORE_BOOTSTRAP_TOKEN)); |
- encryption_handler()->SetKeystoreKeys(BuildEncryptionKeyProto( |
- kRawOldKeystoreKey), |
- trans.GetWrappedTrans()); |
- } |
- PumpLoop(); |
- Mock::VerifyAndClearExpectations(observer()); |
- |
- // Then init the nigori node with a non-backwards compatible set of keys. |
- CreateRootForType(NIGORI); |
- EXPECT_CALL(*observer(), OnPassphraseAccepted()); |
- InitKeystoreMigratedNigori(1, old_keystore_key, old_keystore_key); |
- |
- // Now set some new keystore keys. |
- EXPECT_CALL(*observer(), OnCryptographerStateChanged(_)).Times(AnyNumber()); |
- EXPECT_CALL(*observer(), OnEncryptionComplete()); |
- { |
- google::protobuf::RepeatedPtrField<google::protobuf::string> keys; |
- keys.Add()->assign(kRawOldKeystoreKey); |
- keys.Add()->assign(kRawKeystoreKey); |
- EXPECT_CALL(*observer(), |
- OnBootstrapTokenUpdated(_, KEYSTORE_BOOTSTRAP_TOKEN)); |
- ReadTransaction trans(FROM_HERE, user_share()); |
- encryption_handler()->SetKeystoreKeys(keys, |
- trans.GetWrappedTrans()); |
- } |
- // Pump for any posted tasks. |
- PumpLoop(); |
- Mock::VerifyAndClearExpectations(observer()); |
- |
- // Verify we're still migrated and have proper encryption state. We should |
- // have rotated the keybag so that it's now encrypted with the newest keystore |
- // key (instead of the old gaia key). |
- EXPECT_TRUE(encryption_handler()->MigratedToKeystore()); |
- EXPECT_TRUE(GetCryptographer()->is_ready()); |
- EXPECT_EQ(encryption_handler()->GetPassphraseType(), KEYSTORE_PASSPHRASE); |
- EXPECT_FALSE(encryption_handler()->IsEncryptEverythingEnabled()); |
- VerifyMigratedNigori(KEYSTORE_PASSPHRASE, kKeystoreKey); |
-} |
- |
-// Trigger a key rotation upon when a pending gaia passphrase is resolved. |
-TEST_F(SyncEncryptionHandlerImplTest, RotateKeysAfterPendingGaiaResolved) { |
- const char kOldGaiaKey[] = "old_gaia_key"; |
- const char kRawOldKeystoreKey[] = "old_keystore_key"; |
- |
- EXPECT_CALL(*observer(), OnPassphraseRequired(_, _)); |
- InitUnmigratedNigori(kOldGaiaKey, IMPLICIT_PASSPHRASE); |
- |
- { |
- // Pass multiple keystore keys, signaling a rotation has happened. |
- google::protobuf::RepeatedPtrField<google::protobuf::string> keys; |
- keys.Add()->assign(kRawOldKeystoreKey); |
- keys.Add()->assign(kRawKeystoreKey); |
- ReadTransaction trans(FROM_HERE, user_share()); |
- EXPECT_CALL(*observer(), |
- OnBootstrapTokenUpdated(_, KEYSTORE_BOOTSTRAP_TOKEN)); |
- encryption_handler()->SetKeystoreKeys(keys, |
- trans.GetWrappedTrans()); |
- } |
- PumpLoop(); |
- Mock::VerifyAndClearExpectations(observer()); |
- |
- // Resolve the pending keys. This should trigger the key rotation. |
- EXPECT_CALL(*observer(), |
- OnCryptographerStateChanged(_)).Times(AnyNumber()); |
- EXPECT_CALL(*observer(), |
- OnPassphraseAccepted()); |
- EXPECT_CALL(*observer(), |
- OnPassphraseTypeChanged(KEYSTORE_PASSPHRASE, _)); |
- EXPECT_CALL(*observer(), |
- OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)); |
- EXPECT_CALL(*observer(), |
- OnEncryptionComplete()).Times(AtLeast(1)); |
- EXPECT_FALSE(encryption_handler()->MigratedToKeystore()); |
- encryption_handler()->SetDecryptionPassphrase(kOldGaiaKey); |
- EXPECT_TRUE(encryption_handler()->MigratedToKeystore()); |
- EXPECT_EQ(KEYSTORE_PASSPHRASE, encryption_handler()->GetPassphraseType()); |
- VerifyMigratedNigori(KEYSTORE_PASSPHRASE, kKeystoreKey); |
-} |
- |
-// When signing in for the first time, make sure we can rotate keys if we |
-// already have a keystore migrated nigori. |
-TEST_F(SyncEncryptionHandlerImplTest, RotateKeysGaiaDefaultOnInit) { |
- // Destroy the existing nigori node so we init without a nigori node. |
- TearDown(); |
- test_user_share_.SetUp(); |
- SetUpEncryption(); |
- |
- const char kOldGaiaKey[] = "old_gaia_key"; |
- const char kRawOldKeystoreKey[] = "old_keystore_key"; |
- std::string old_keystore_key; |
- base::Base64Encode(kRawOldKeystoreKey, &old_keystore_key); |
- |
- // Set two keys, signaling that a rotation has been performed. No nigori |
- // node is present yet, so we can't rotate. |
- { |
- google::protobuf::RepeatedPtrField<google::protobuf::string> keys; |
- keys.Add()->assign(kRawOldKeystoreKey); |
- keys.Add()->assign(kRawKeystoreKey); |
- EXPECT_CALL(*observer(), |
- OnBootstrapTokenUpdated(_, KEYSTORE_BOOTSTRAP_TOKEN)); |
- ReadTransaction trans(FROM_HERE, user_share()); |
- encryption_handler()->SetKeystoreKeys(keys, |
- trans.GetWrappedTrans()); |
- } |
- |
- // Then init the nigori node with an old set of keys. |
- CreateRootForType(NIGORI); |
- EXPECT_CALL(*observer(), OnPassphraseAccepted()); |
- InitKeystoreMigratedNigori(1, kOldGaiaKey, old_keystore_key); |
- PumpLoop(); |
- Mock::VerifyAndClearExpectations(observer()); |
- |
- // Verify we're still migrated and have proper encryption state. We should |
- // have rotated the keybag so that it's now encrypted with the newest keystore |
- // key (instead of the old gaia key). |
- EXPECT_TRUE(encryption_handler()->MigratedToKeystore()); |
- EXPECT_TRUE(GetCryptographer()->is_ready()); |
- EXPECT_EQ(encryption_handler()->GetPassphraseType(), KEYSTORE_PASSPHRASE); |
- EXPECT_FALSE(encryption_handler()->IsEncryptEverythingEnabled()); |
- VerifyMigratedNigori(KEYSTORE_PASSPHRASE, kKeystoreKey); |
-} |
- |
-// Trigger a key rotation when a migrated nigori (with an old keystore key) is |
-// applied. |
-TEST_F(SyncEncryptionHandlerImplTest, RotateKeysWhenMigratedNigoriArrives) { |
- const char kOldGaiaKey[] = "old_gaia_key"; |
- const char kRawOldKeystoreKey[] = "old_keystore_key"; |
- std::string old_keystore_key; |
- base::Base64Encode(kRawOldKeystoreKey, &old_keystore_key); |
- |
- EXPECT_CALL(*observer(), OnPassphraseRequired(_, _)); |
- InitUnmigratedNigori(kOldGaiaKey, IMPLICIT_PASSPHRASE); |
- |
- { |
- // Pass multiple keystore keys, signaling a rotation has happened. |
- google::protobuf::RepeatedPtrField<google::protobuf::string> keys; |
- keys.Add()->assign(kRawOldKeystoreKey); |
- keys.Add()->assign(kRawKeystoreKey); |
- ReadTransaction trans(FROM_HERE, user_share()); |
- EXPECT_CALL(*observer(), |
- OnBootstrapTokenUpdated(_, KEYSTORE_BOOTSTRAP_TOKEN)); |
- encryption_handler()->SetKeystoreKeys(keys, |
- trans.GetWrappedTrans()); |
- } |
- PumpLoop(); |
- Mock::VerifyAndClearExpectations(observer()); |
- |
- // Now simulate downloading a nigori node that was migrated before the |
- // keys were rotated, and hence still encrypt with the old gaia key. |
- EXPECT_CALL(*observer(), |
- OnCryptographerStateChanged(_)).Times(AnyNumber()); |
- EXPECT_CALL(*observer(), |
- OnPassphraseAccepted()); |
- EXPECT_CALL(*observer(), |
- OnPassphraseTypeChanged(KEYSTORE_PASSPHRASE, _)); |
- EXPECT_CALL(*observer(), |
- OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)); |
- EXPECT_CALL(*observer(), |
- OnEncryptionComplete()).Times(AtLeast(1)); |
- { |
- sync_pb::NigoriSpecifics nigori = BuildMigratedNigori( |
- KEYSTORE_PASSPHRASE, |
- 1, |
- kOldGaiaKey, |
- old_keystore_key); |
- // Update the encryption handler. |
- WriteTransaction trans(FROM_HERE, user_share()); |
- encryption_handler()->ApplyNigoriUpdate( |
- nigori, |
- trans.GetWrappedTrans()); |
- } |
- EXPECT_FALSE(encryption_handler()->MigratedToKeystore()); |
- PumpLoop(); |
- |
- EXPECT_TRUE(encryption_handler()->MigratedToKeystore()); |
- EXPECT_EQ(KEYSTORE_PASSPHRASE, encryption_handler()->GetPassphraseType()); |
- VerifyMigratedNigori(KEYSTORE_PASSPHRASE, kKeystoreKey); |
-} |
- |
-// Verify that performing a migration while having more than one keystore key |
-// preserves a custom passphrase. |
-TEST_F(SyncEncryptionHandlerImplTest, RotateKeysUnmigratedCustomPassphrase) { |
- const char kCustomPass[] = "custom_passphrase"; |
- const char kRawOldKeystoreKey[] = "old_keystore_key"; |
- |
- EXPECT_CALL(*observer(), OnPassphraseRequired(_, _)); |
- InitUnmigratedNigori(kCustomPass, CUSTOM_PASSPHRASE); |
- |
- { |
- // Pass multiple keystore keys, signaling a rotation has happened. |
- google::protobuf::RepeatedPtrField<google::protobuf::string> keys; |
- keys.Add()->assign(kRawOldKeystoreKey); |
- keys.Add()->assign(kRawKeystoreKey); |
- ReadTransaction trans(FROM_HERE, user_share()); |
- EXPECT_CALL(*observer(), |
- OnBootstrapTokenUpdated(_, KEYSTORE_BOOTSTRAP_TOKEN)); |
- encryption_handler()->SetKeystoreKeys(keys, |
- trans.GetWrappedTrans()); |
- } |
- PumpLoop(); |
- Mock::VerifyAndClearExpectations(observer()); |
- |
- // Pass the decryption passphrase. This will also trigger the migration, |
- // but should not overwrite the default key. |
- EXPECT_CALL(*observer(), |
- OnCryptographerStateChanged(_)).Times(AnyNumber()); |
- EXPECT_CALL(*observer(), |
- OnPassphraseAccepted()); |
- EXPECT_CALL(*observer(), |
- OnEncryptedTypesChanged(_, true)); |
- SyncEncryptionHandler::NigoriState captured_nigori_state; |
- EXPECT_CALL(*observer(), OnLocalSetPassphraseEncryption(_)) |
- .WillOnce(testing::SaveArg<0>(&captured_nigori_state)); |
- EXPECT_CALL(*observer(), |
- OnEncryptionComplete()).Times(AnyNumber()); |
- std::string captured_bootstrap_token; |
- EXPECT_CALL(*observer(), |
- OnBootstrapTokenUpdated(_, PASSPHRASE_BOOTSTRAP_TOKEN)) |
- .WillOnce(testing::SaveArg<0>(&captured_bootstrap_token)); |
- encryption_handler()->SetDecryptionPassphrase(kCustomPass); |
- Mock::VerifyAndClearExpectations(observer()); |
- |
- VerifyMigratedNigori(CUSTOM_PASSPHRASE, kCustomPass); |
- |
- const base::Time migration_time = encryption_handler()->migration_time(); |
- VerifyRestoreAfterCustomPassphrase(TimeToProtoTime(migration_time), |
- kCustomPass, captured_bootstrap_token, |
- captured_nigori_state, CUSTOM_PASSPHRASE); |
-} |
- |
-// Verify that a key rotation done after we've migrated a custom passphrase |
-// nigori node preserves the custom passphrase. |
-TEST_F(SyncEncryptionHandlerImplTest, RotateKeysMigratedCustomPassphrase) { |
- const char kCustomPass[] = "custom_passphrase"; |
- const char kRawOldKeystoreKey[] = "old_keystore_key"; |
- |
- KeyParams custom_key = {"localhost", "dummy", kCustomPass}; |
- GetCryptographer()->AddKey(custom_key); |
- |
- const int64_t migration_time = 1; |
- InitCustomPassMigratedNigori(migration_time, kCustomPass); |
- VerifyMigratedNigoriWithTimestamp(migration_time, CUSTOM_PASSPHRASE, |
- kCustomPass); |
- |
- SyncEncryptionHandler::NigoriState captured_nigori_state; |
- { |
- // Pass multiple keystore keys, signaling a rotation has happened. |
- google::protobuf::RepeatedPtrField<google::protobuf::string> keys; |
- keys.Add()->assign(kRawOldKeystoreKey); |
- keys.Add()->assign(kRawKeystoreKey); |
- ReadTransaction trans(FROM_HERE, user_share()); |
- EXPECT_CALL(*observer(), |
- OnBootstrapTokenUpdated(_, KEYSTORE_BOOTSTRAP_TOKEN)); |
- EXPECT_CALL(*observer(), |
- OnCryptographerStateChanged(_)).Times(AnyNumber()); |
- EXPECT_CALL(*observer(), OnLocalSetPassphraseEncryption(_)) |
- .WillOnce(testing::SaveArg<0>(&captured_nigori_state)); |
- encryption_handler()->SetKeystoreKeys(keys, |
- trans.GetWrappedTrans()); |
- } |
- PumpLoop(); |
- Mock::VerifyAndClearExpectations(observer()); |
- |
- VerifyMigratedNigoriWithTimestamp(migration_time, CUSTOM_PASSPHRASE, |
- kCustomPass); |
- |
- // We need the passphrase bootstrap token, but OnBootstrapTokenUpdated(_, |
- // PASSPHRASE_BOOTSTRAP_TOKEN) has not been invoked (because it was invoked |
- // during a previous instance) so get it from the Cryptographer. |
- std::string passphrase_bootstrap_token; |
- GetCryptographer()->GetBootstrapToken(&passphrase_bootstrap_token); |
- VerifyRestoreAfterCustomPassphrase(migration_time, kCustomPass, |
- passphrase_bootstrap_token, |
- captured_nigori_state, CUSTOM_PASSPHRASE); |
-} |
- |
-// Verify that the client can gracefully handle a nigori node that is missing |
-// the keystore migration time field. |
-TEST_F(SyncEncryptionHandlerImplTest, MissingKeystoreMigrationTime) { |
- EXPECT_CALL(*observer(), |
- OnCryptographerStateChanged(_)).Times(AnyNumber()); |
- EXPECT_CALL(*observer(), |
- OnPassphraseRequired(_, _)); |
- EXPECT_CALL(*observer(), |
- OnEncryptedTypesChanged(_, false)); |
- encryption_handler()->Init(); |
- Mock::VerifyAndClearExpectations(observer()); |
- |
- // Now simulate downloading a nigori node that that is missing the keystore |
- // migration time. It should be interpreted properly, and the passphrase type |
- // should switch to keystore passphrase. |
- EXPECT_CALL(*observer(), |
- OnCryptographerStateChanged(_)).Times(AnyNumber()); |
- EXPECT_CALL(*observer(), |
- OnPassphraseRequired(_, _)); |
- EXPECT_CALL(*observer(), |
- OnPassphraseTypeChanged(KEYSTORE_PASSPHRASE, _)); |
- { |
- sync_pb::NigoriSpecifics nigori = BuildMigratedNigori( |
- KEYSTORE_PASSPHRASE, |
- 1, |
- kKeystoreKey, |
- kKeystoreKey); |
- nigori.clear_keystore_migration_time(); |
- // Update the encryption handler. |
- WriteTransaction trans(FROM_HERE, user_share()); |
- encryption_handler()->ApplyNigoriUpdate( |
- nigori, |
- trans.GetWrappedTrans()); |
- } |
- Mock::VerifyAndClearExpectations(observer()); |
- |
- // Now provide the keystore key to fully initialize the cryptographer. |
- EXPECT_CALL(*observer(), |
- OnCryptographerStateChanged(_)).Times(AnyNumber()); |
- EXPECT_CALL(*observer(), |
- OnBootstrapTokenUpdated(_, KEYSTORE_BOOTSTRAP_TOKEN)); |
- { |
- ReadTransaction trans(FROM_HERE, user_share()); |
- encryption_handler()->SetKeystoreKeys(BuildEncryptionKeyProto( |
- kRawKeystoreKey), |
- trans.GetWrappedTrans()); |
- } |
-} |
- |
-} // namespace syncer |