Commit 88ae02d7 authored by Maksim Moskvitin's avatar Maksim Moskvitin Committed by Commit Bot

[Sync:USS] Support syncing with IMPLICIT_PASSPHRASE

IMPLICIT_PASSPHRASE treated as a passphrase type, which requires
user-provided passphrase for decryption. We support it because we
still have some users with very old Nigori's.

This CL doesn't introduce support for keystore migration, setting up or
changing implicit passphrase.

Bug: 922900
Change-Id: I3cb6e0119f141ab1bd4fce2cc1db7c70f2d2cc2b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1860415
Commit-Queue: Maksim Moskvitin <mmoskvitin@google.com>
Auto-Submit: Maksim Moskvitin <mmoskvitin@google.com>
Reviewed-by: default avatarMikel Astiz <mastiz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#706159}
parent d0412f5a
...@@ -157,25 +157,13 @@ bool IsValidNigoriSpecifics(const NigoriSpecifics& specifics) { ...@@ -157,25 +157,13 @@ bool IsValidNigoriSpecifics(const NigoriSpecifics& specifics) {
DLOG(ERROR) << "Specifics contains empty encryption_keybag."; DLOG(ERROR) << "Specifics contains empty encryption_keybag.";
return false; return false;
} }
// TODO(mmoskvitin): Revisit this because of IMPLICIT_PASSPHRASE, which also
// contradicts a later comment.
if (!specifics.has_passphrase_type()) {
DLOG(ERROR) << "Specifics has no passphrase_type.";
return false;
}
switch (ProtoPassphraseInt32ToProtoEnum(specifics.passphrase_type())) { switch (ProtoPassphraseInt32ToProtoEnum(specifics.passphrase_type())) {
case NigoriSpecifics::UNKNOWN: case NigoriSpecifics::UNKNOWN:
DLOG(ERROR) << "Received unknown passphrase type with value: " DLOG(ERROR) << "Received unknown passphrase type with value: "
<< specifics.passphrase_type(); << specifics.passphrase_type();
return false; return false;
case NigoriSpecifics::IMPLICIT_PASSPHRASE: case NigoriSpecifics::IMPLICIT_PASSPHRASE:
// TODO(crbug.com/922900): we hope that IMPLICIT_PASSPHRASE support is not return true;
// needed in new implementation. In case we need to continue migration to
// keystore we will need to support it.
// Note: in case passphrase_type is not set, we also end up here, because
// IMPLICIT_PASSPHRASE is a default value.
DLOG(ERROR) << "IMPLICIT_PASSPHRASE is not supported.";
return false;
case NigoriSpecifics::KEYSTORE_PASSPHRASE: case NigoriSpecifics::KEYSTORE_PASSPHRASE:
if (specifics.keystore_decryptor_token().blob().empty()) { if (specifics.keystore_decryptor_token().blob().empty()) {
DLOG(ERROR) << "Keystore Nigori should have filled " DLOG(ERROR) << "Keystore Nigori should have filled "
...@@ -205,11 +193,8 @@ bool IsValidNigoriSpecifics(const NigoriSpecifics& specifics) { ...@@ -205,11 +193,8 @@ bool IsValidNigoriSpecifics(const NigoriSpecifics& specifics) {
bool IsValidPassphraseTransition( bool IsValidPassphraseTransition(
NigoriSpecifics::PassphraseType old_passphrase_type, NigoriSpecifics::PassphraseType old_passphrase_type,
NigoriSpecifics::PassphraseType new_passphrase_type) { NigoriSpecifics::PassphraseType new_passphrase_type) {
// We never allow setting IMPLICIT_PASSPHRASE as current passphrase type.
DCHECK_NE(old_passphrase_type, NigoriSpecifics::IMPLICIT_PASSPHRASE);
// We assume that |new_passphrase_type| is valid. // We assume that |new_passphrase_type| is valid.
DCHECK_NE(new_passphrase_type, NigoriSpecifics::UNKNOWN); DCHECK_NE(new_passphrase_type, NigoriSpecifics::UNKNOWN);
DCHECK_NE(new_passphrase_type, NigoriSpecifics::IMPLICIT_PASSPHRASE);
if (old_passphrase_type == new_passphrase_type) { if (old_passphrase_type == new_passphrase_type) {
return true; return true;
...@@ -218,10 +203,8 @@ bool IsValidPassphraseTransition( ...@@ -218,10 +203,8 @@ bool IsValidPassphraseTransition(
case NigoriSpecifics::UNKNOWN: case NigoriSpecifics::UNKNOWN:
// This can happen iff we have not synced local state yet, so we accept // This can happen iff we have not synced local state yet, so we accept
// any valid passphrase type (invalid filtered before). // any valid passphrase type (invalid filtered before).
return true;
case NigoriSpecifics::IMPLICIT_PASSPHRASE: case NigoriSpecifics::IMPLICIT_PASSPHRASE:
NOTREACHED(); return true;
return false;
case NigoriSpecifics::KEYSTORE_PASSPHRASE: case NigoriSpecifics::KEYSTORE_PASSPHRASE:
return new_passphrase_type == NigoriSpecifics::CUSTOM_PASSPHRASE || return new_passphrase_type == NigoriSpecifics::CUSTOM_PASSPHRASE ||
new_passphrase_type == NigoriSpecifics::TRUSTED_VAULT_PASSPHRASE; new_passphrase_type == NigoriSpecifics::TRUSTED_VAULT_PASSPHRASE;
...@@ -450,7 +433,6 @@ void NigoriSyncBridgeImpl::SetEncryptionPassphrase( ...@@ -450,7 +433,6 @@ void NigoriSyncBridgeImpl::SetEncryptionPassphrase(
const std::string& passphrase) { const std::string& passphrase) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
switch (state_.passphrase_type) { switch (state_.passphrase_type) {
case NigoriSpecifics::IMPLICIT_PASSPHRASE:
case NigoriSpecifics::UNKNOWN: case NigoriSpecifics::UNKNOWN:
NOTREACHED(); NOTREACHED();
return; return;
...@@ -464,6 +446,7 @@ void NigoriSyncBridgeImpl::SetEncryptionPassphrase( ...@@ -464,6 +446,7 @@ void NigoriSyncBridgeImpl::SetEncryptionPassphrase(
// TODO(crbug.com/922900): investigate whether we need to call // TODO(crbug.com/922900): investigate whether we need to call
// OnPassphraseRequired() to prompt for decryption passphrase. // OnPassphraseRequired() to prompt for decryption passphrase.
return; return;
case NigoriSpecifics::IMPLICIT_PASSPHRASE:
case NigoriSpecifics::KEYSTORE_PASSPHRASE: case NigoriSpecifics::KEYSTORE_PASSPHRASE:
case NigoriSpecifics::TRUSTED_VAULT_PASSPHRASE: case NigoriSpecifics::TRUSTED_VAULT_PASSPHRASE:
if (state_.pending_keys.has_value()) { if (state_.pending_keys.has_value()) {
...@@ -785,10 +768,9 @@ base::Optional<ModelError> NigoriSyncBridgeImpl::UpdateLocalState( ...@@ -785,10 +768,9 @@ base::Optional<ModelError> NigoriSyncBridgeImpl::UpdateLocalState(
specifics.encryption_keybag(); specifics.encryption_keybag();
switch (state_.passphrase_type) { switch (state_.passphrase_type) {
case NigoriSpecifics::UNKNOWN: case NigoriSpecifics::UNKNOWN:
case NigoriSpecifics::IMPLICIT_PASSPHRASE: // NigoriSpecifics with UNKNOWN type is not valid and shouldn't reach
// NigoriSpecifics with UNKNOWN or IMPLICIT_PASSPHRASE type is not valid // this codepath. We just updated |passphrase_type_| from specifics, so
// and shouldn't reach this codepath. We just updated |passphrase_type_| // it can't be in this state as well.
// from specifics, so it can't be in these states as well.
NOTREACHED(); NOTREACHED();
break; break;
case NigoriSpecifics::KEYSTORE_PASSPHRASE: { case NigoriSpecifics::KEYSTORE_PASSPHRASE: {
...@@ -803,6 +785,7 @@ base::Optional<ModelError> NigoriSyncBridgeImpl::UpdateLocalState( ...@@ -803,6 +785,7 @@ base::Optional<ModelError> NigoriSyncBridgeImpl::UpdateLocalState(
state_.custom_passphrase_key_derivation_params = state_.custom_passphrase_key_derivation_params =
GetKeyDerivationParamsFromSpecifics(specifics); GetKeyDerivationParamsFromSpecifics(specifics);
FALLTHROUGH; FALLTHROUGH;
case NigoriSpecifics::IMPLICIT_PASSPHRASE:
case NigoriSpecifics::FROZEN_IMPLICIT_PASSPHRASE: case NigoriSpecifics::FROZEN_IMPLICIT_PASSPHRASE:
case NigoriSpecifics::TRUSTED_VAULT_PASSPHRASE: case NigoriSpecifics::TRUSTED_VAULT_PASSPHRASE:
UpdateCryptographerFromNonKeystoreNigori(encryption_keybag); UpdateCryptographerFromNonKeystoreNigori(encryption_keybag);
...@@ -1025,10 +1008,6 @@ std::string NigoriSyncBridgeImpl::PackExplicitPassphraseKeyForTesting( ...@@ -1025,10 +1008,6 @@ std::string NigoriSyncBridgeImpl::PackExplicitPassphraseKeyForTesting(
base::Time NigoriSyncBridgeImpl::GetExplicitPassphraseTime() const { base::Time NigoriSyncBridgeImpl::GetExplicitPassphraseTime() const {
switch (state_.passphrase_type) { switch (state_.passphrase_type) {
case NigoriSpecifics::IMPLICIT_PASSPHRASE: case NigoriSpecifics::IMPLICIT_PASSPHRASE:
// IMPLICIT_PASSPHRASE type isn't supported and should be never set as
// |passphrase_type_|;
NOTREACHED();
return base::Time();
case NigoriSpecifics::UNKNOWN: case NigoriSpecifics::UNKNOWN:
case NigoriSpecifics::KEYSTORE_PASSPHRASE: case NigoriSpecifics::KEYSTORE_PASSPHRASE:
case NigoriSpecifics::TRUSTED_VAULT_PASSPHRASE: case NigoriSpecifics::TRUSTED_VAULT_PASSPHRASE:
...@@ -1046,9 +1025,9 @@ KeyDerivationParams NigoriSyncBridgeImpl::GetKeyDerivationParamsForPendingKeys() ...@@ -1046,9 +1025,9 @@ KeyDerivationParams NigoriSyncBridgeImpl::GetKeyDerivationParamsForPendingKeys()
const { const {
switch (state_.passphrase_type) { switch (state_.passphrase_type) {
case NigoriSpecifics::UNKNOWN: case NigoriSpecifics::UNKNOWN:
case NigoriSpecifics::IMPLICIT_PASSPHRASE:
NOTREACHED(); NOTREACHED();
return KeyDerivationParams::CreateWithUnsupportedMethod(); return KeyDerivationParams::CreateWithUnsupportedMethod();
case NigoriSpecifics::IMPLICIT_PASSPHRASE:
case NigoriSpecifics::KEYSTORE_PASSPHRASE: case NigoriSpecifics::KEYSTORE_PASSPHRASE:
case NigoriSpecifics::FROZEN_IMPLICIT_PASSPHRASE: case NigoriSpecifics::FROZEN_IMPLICIT_PASSPHRASE:
case NigoriSpecifics::TRUSTED_VAULT_PASSPHRASE: case NigoriSpecifics::TRUSTED_VAULT_PASSPHRASE:
...@@ -1066,8 +1045,8 @@ void NigoriSyncBridgeImpl::MaybeNotifyOfPendingKeys() const { ...@@ -1066,8 +1045,8 @@ void NigoriSyncBridgeImpl::MaybeNotifyOfPendingKeys() const {
switch (state_.passphrase_type) { switch (state_.passphrase_type) {
case NigoriSpecifics::UNKNOWN: case NigoriSpecifics::UNKNOWN:
case NigoriSpecifics::IMPLICIT_PASSPHRASE:
return; return;
case NigoriSpecifics::IMPLICIT_PASSPHRASE:
case NigoriSpecifics::KEYSTORE_PASSPHRASE: case NigoriSpecifics::KEYSTORE_PASSPHRASE:
case NigoriSpecifics::CUSTOM_PASSPHRASE: case NigoriSpecifics::CUSTOM_PASSPHRASE:
case NigoriSpecifics::FROZEN_IMPLICIT_PASSPHRASE: case NigoriSpecifics::FROZEN_IMPLICIT_PASSPHRASE:
...@@ -1088,7 +1067,6 @@ void NigoriSyncBridgeImpl::MaybeNotifyOfPendingKeys() const { ...@@ -1088,7 +1067,6 @@ void NigoriSyncBridgeImpl::MaybeNotifyOfPendingKeys() const {
void NigoriSyncBridgeImpl::MaybeNotifyBootstrapTokenUpdated() const { void NigoriSyncBridgeImpl::MaybeNotifyBootstrapTokenUpdated() const {
switch (state_.passphrase_type) { switch (state_.passphrase_type) {
case NigoriSpecifics::UNKNOWN: case NigoriSpecifics::UNKNOWN:
case NigoriSpecifics::IMPLICIT_PASSPHRASE:
NOTREACHED(); NOTREACHED();
return; return;
case NigoriSpecifics::KEYSTORE_PASSPHRASE: case NigoriSpecifics::KEYSTORE_PASSPHRASE:
...@@ -1101,6 +1079,7 @@ void NigoriSyncBridgeImpl::MaybeNotifyBootstrapTokenUpdated() const { ...@@ -1101,6 +1079,7 @@ void NigoriSyncBridgeImpl::MaybeNotifyBootstrapTokenUpdated() const {
// prefs. // prefs.
NOTIMPLEMENTED(); NOTIMPLEMENTED();
return; return;
case NigoriSpecifics::IMPLICIT_PASSPHRASE:
case NigoriSpecifics::FROZEN_IMPLICIT_PASSPHRASE: case NigoriSpecifics::FROZEN_IMPLICIT_PASSPHRASE:
case NigoriSpecifics::CUSTOM_PASSPHRASE: case NigoriSpecifics::CUSTOM_PASSPHRASE:
// |packed_custom_passphrase_key| will be empty in case serialization or // |packed_custom_passphrase_key| will be empty in case serialization or
......
...@@ -391,6 +391,42 @@ TEST_F(NigoriSyncBridgeImplTest, ShouldNotifyObserversOnInit) { ...@@ -391,6 +391,42 @@ TEST_F(NigoriSyncBridgeImplTest, ShouldNotifyObserversOnInit) {
bridge()->Init(); bridge()->Init();
} }
// Tests that bridge support Nigori with IMPLICIT_PASSPHRASE.
TEST_F(NigoriSyncBridgeImplTest, ShouldAcceptKeysFromImplicitPassphraseNigori) {
const KeyParams kKeyParams = Pbkdf2KeyParams("password");
std::unique_ptr<CryptographerImpl> temp_cryptographer =
CryptographerImpl::FromSingleKeyForTesting(kKeyParams.password,
kKeyParams.derivation_params);
EntityData entity_data;
*entity_data.specifics.mutable_nigori() =
sync_pb::NigoriSpecifics::default_instance();
ASSERT_TRUE(temp_cryptographer->Encrypt(
temp_cryptographer->ToProto().key_bag(),
entity_data.specifics.mutable_nigori()->mutable_encryption_keybag()));
EXPECT_CALL(*observer(), OnCryptographerStateChanged(
NotNull(), /*has_pending_keys=*/true));
EXPECT_CALL(
*observer(),
OnPassphraseRequired(
/*reason=*/REASON_DECRYPTION,
/*key_derivation_params=*/KeyDerivationParams::CreateForPbkdf2(),
/*pending_keys=*/
EncryptedDataEq(entity_data.specifics.nigori().encryption_keybag())));
EXPECT_THAT(bridge()->MergeSyncData(std::move(entity_data)),
Eq(base::nullopt));
EXPECT_CALL(*observer(), OnPassphraseAccepted());
EXPECT_CALL(*observer(), OnCryptographerStateChanged(
NotNull(), /*has_pending_keys=*/false));
bridge()->SetDecryptionPassphrase(kKeyParams.password);
const Cryptographer& cryptographer = bridge()->GetCryptographerForTesting();
EXPECT_THAT(cryptographer, CanDecryptWith(kKeyParams));
EXPECT_THAT(cryptographer, HasDefaultKeyDerivedFrom(kKeyParams));
}
// Simplest case of keystore Nigori: we have only one keystore key and no old // Simplest case of keystore Nigori: we have only one keystore key and no old
// keys. This keystore key is encrypted in both encryption_keybag and // keys. This keystore key is encrypted in both encryption_keybag and
// keystore_decryptor_token. Client receives such Nigori if initialization of // keystore_decryptor_token. Client receives such Nigori if initialization of
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment