Commit 280a69e4 authored by Maksim Moskvitin's avatar Maksim Moskvitin Committed by Commit Bot

Support transitions from trusted vault passphrase

This CL supports transitions from trusted vault passphrase to keystore
and custom passphrases. To avoid data corruptions by buggy clients the
bridge verifies that the remote keybag contains the last trusted vault
key, which was used as the default key. Since browser restart can
happen in between of receiving the remote update and decryption of the
new remote keybag, |last_trusted_vault_key| stored in NigoriLocalData.

Bug: 1020084
Change-Id: Ica654898a3499f599258bf9e65eb8d91580fcc2f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2087766
Commit-Queue: Maksim Moskvitin <mmoskvitin@google.com>
Reviewed-by: default avatarMikel Astiz <mastiz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#747697}
parent e09f4624
...@@ -152,6 +152,12 @@ NigoriState NigoriState::CreateFromLocalProto( ...@@ -152,6 +152,12 @@ NigoriState NigoriState::CreateFromLocalProto(
state.pending_keystore_decryptor_token = state.pending_keystore_decryptor_token =
proto.pending_keystore_decryptor_token(); proto.pending_keystore_decryptor_token();
} }
if (proto.has_last_default_trusted_vault_key_name()) {
state.last_default_trusted_vault_key_name =
proto.last_default_trusted_vault_key_name();
}
return state; return state;
} }
...@@ -210,6 +216,10 @@ sync_pb::NigoriModel NigoriState::ToLocalProto() const { ...@@ -210,6 +216,10 @@ sync_pb::NigoriModel NigoriState::ToLocalProto() const {
*proto.mutable_pending_keystore_decryptor_token() = *proto.mutable_pending_keystore_decryptor_token() =
*pending_keystore_decryptor_token; *pending_keystore_decryptor_token;
} }
if (last_default_trusted_vault_key_name.has_value()) {
proto.set_last_default_trusted_vault_key_name(
*last_default_trusted_vault_key_name);
}
return proto; return proto;
} }
...@@ -236,6 +246,8 @@ sync_pb::NigoriSpecifics NigoriState::ToSpecificsProto() const { ...@@ -236,6 +246,8 @@ sync_pb::NigoriSpecifics NigoriState::ToSpecificsProto() const {
UpdateSpecificsFromKeyDerivationParams( UpdateSpecificsFromKeyDerivationParams(
*custom_passphrase_key_derivation_params, &specifics); *custom_passphrase_key_derivation_params, &specifics);
} }
// TODO(crbug.com/1020084): populate |keystore_decryptor_token| for trusted
// vault passphrase to allow rollbacks.
if (passphrase_type == sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE) { if (passphrase_type == sync_pb::NigoriSpecifics::KEYSTORE_PASSPHRASE) {
// TODO(crbug.com/922900): it seems possible to have corrupted // TODO(crbug.com/922900): it seems possible to have corrupted
// |pending_keystore_decryptor_token| and an ability to recover it in case // |pending_keystore_decryptor_token| and an ability to recover it in case
...@@ -277,6 +289,8 @@ NigoriState NigoriState::Clone() const { ...@@ -277,6 +289,8 @@ NigoriState NigoriState::Clone() const {
result.encrypt_everything = encrypt_everything; result.encrypt_everything = encrypt_everything;
result.keystore_keys_cryptographer = keystore_keys_cryptographer->Clone(); result.keystore_keys_cryptographer = keystore_keys_cryptographer->Clone();
result.pending_keystore_decryptor_token = pending_keystore_decryptor_token; result.pending_keystore_decryptor_token = pending_keystore_decryptor_token;
result.last_default_trusted_vault_key_name =
last_default_trusted_vault_key_name;
return result; return result;
} }
......
...@@ -82,6 +82,10 @@ struct NigoriState { ...@@ -82,6 +82,10 @@ struct NigoriState {
// can't be decrypted right after remote update arrival due to lack of // can't be decrypted right after remote update arrival due to lack of
// keystore keys. May be set only for keystore Nigori. // keystore keys. May be set only for keystore Nigori.
base::Optional<sync_pb::EncryptedData> pending_keystore_decryptor_token; base::Optional<sync_pb::EncryptedData> pending_keystore_decryptor_token;
// The name of the latest available trusted vault key that was used as the
// default encryption key.
base::Optional<std::string> last_default_trusted_vault_key_name;
}; };
} // namespace syncer } // namespace syncer
......
...@@ -198,13 +198,8 @@ bool IsValidPassphraseTransition( ...@@ -198,13 +198,8 @@ bool IsValidPassphraseTransition(
case NigoriSpecifics::CUSTOM_PASSPHRASE: case NigoriSpecifics::CUSTOM_PASSPHRASE:
return false; return false;
case NigoriSpecifics::TRUSTED_VAULT_PASSPHRASE: case NigoriSpecifics::TRUSTED_VAULT_PASSPHRASE:
// TODO(crbug.com/984940): The below should be allowed for return new_passphrase_type == NigoriSpecifics::CUSTOM_PASSPHRASE ||
// CUSTOM_PASSPHRASE and KEYSTORE_PASSPHRASE but it requires carefully new_passphrase_type == NigoriSpecifics::KEYSTORE_PASSPHRASE;
// verifying that the client triggering the transition already had access
// to the trusted vault passphrase (e.g. the new keybag must be a
// superset of the old and the default key must have changed).
NOTIMPLEMENTED();
return false;
} }
NOTREACHED(); NOTREACHED();
return false; return false;
...@@ -653,6 +648,9 @@ void NigoriSyncBridgeImpl::AddTrustedVaultDecryptionKeys( ...@@ -653,6 +648,9 @@ void NigoriSyncBridgeImpl::AddTrustedVaultDecryptionKeys(
return; return;
} }
state_.last_default_trusted_vault_key_name =
state_.cryptographer->GetDefaultEncryptionKeyName();
storage_->StoreData(SerializeAsNigoriLocalData()); storage_->StoreData(SerializeAsNigoriLocalData());
broadcasting_observer_->OnCryptographerStateChanged( broadcasting_observer_->OnCryptographerStateChanged(
state_.cryptographer.get(), state_.pending_keys.has_value()); state_.cryptographer.get(), state_.pending_keys.has_value());
...@@ -995,6 +993,17 @@ base::Optional<ModelError> NigoriSyncBridgeImpl::TryDecryptPendingKeysWith( ...@@ -995,6 +993,17 @@ base::Optional<ModelError> NigoriSyncBridgeImpl::TryDecryptPendingKeysWith(
"Received keybag is missing the new default key."); "Received keybag is missing the new default key.");
} }
if (state_.last_default_trusted_vault_key_name.has_value() &&
!new_key_bag.HasKey(*state_.last_default_trusted_vault_key_name)) {
// Protocol violation.
return ModelError(FROM_HERE,
"Received keybag is missing the last trusted vault key.");
}
// Reset |last_default_trusted_vault_key_name| as |state_| might go out of
// TRUSTED_VAULT passphrase type. The callers are responsible to set it again
// if needed.
state_.last_default_trusted_vault_key_name = base::nullopt;
state_.cryptographer->EmplaceKeysFrom(new_key_bag); state_.cryptographer->EmplaceKeysFrom(new_key_bag);
state_.cryptographer->SelectDefaultEncryptionKey(new_default_key_name); state_.cryptographer->SelectDefaultEncryptionKey(new_default_key_name);
state_.pending_keys.reset(); state_.pending_keys.reset();
...@@ -1054,6 +1063,7 @@ void NigoriSyncBridgeImpl::ApplyDisableSyncChanges() { ...@@ -1054,6 +1063,7 @@ void NigoriSyncBridgeImpl::ApplyDisableSyncChanges() {
state_.custom_passphrase_time = base::Time(); state_.custom_passphrase_time = base::Time();
state_.keystore_migration_time = base::Time(); state_.keystore_migration_time = base::Time();
state_.custom_passphrase_key_derivation_params = base::nullopt; state_.custom_passphrase_key_derivation_params = base::nullopt;
state_.last_default_trusted_vault_key_name = base::nullopt;
broadcasting_observer_->OnCryptographerStateChanged( broadcasting_observer_->OnCryptographerStateChanged(
state_.cryptographer.get(), state_.cryptographer.get(),
/*has_pending_keys=*/false); /*has_pending_keys=*/false);
......
...@@ -90,6 +90,11 @@ message NigoriModel { ...@@ -90,6 +90,11 @@ message NigoriModel {
// Encryptor keystore decryptor token. Used for decryption of keystore Nigori // Encryptor keystore decryptor token. Used for decryption of keystore Nigori
// in case keystore keys arrived after NigoriSpecifics. // in case keystore keys arrived after NigoriSpecifics.
optional EncryptedData pending_keystore_decryptor_token = 11; optional EncryptedData pending_keystore_decryptor_token = 11;
// Contains the name of the latest available trusted vault key that was used
// as the default encryption key. Resets when the client go out of pending
// decryption state and transits to other passphrase types.
optional string last_default_trusted_vault_key_name = 12;
} }
// Sync proto to store Nigori data in storage. Proto should be encrypted with // Sync proto to store Nigori data in storage. Proto should be encrypted with
......
...@@ -606,6 +606,7 @@ VISIT_PROTO_FIELDS(const sync_pb::NigoriModel& proto) { ...@@ -606,6 +606,7 @@ VISIT_PROTO_FIELDS(const sync_pb::NigoriModel& proto) {
VISIT_REP(encrypted_types_specifics_field_number); VISIT_REP(encrypted_types_specifics_field_number);
VISIT_REP(keystore_key); VISIT_REP(keystore_key);
VISIT(pending_keystore_decryptor_token); VISIT(pending_keystore_decryptor_token);
VISIT(last_default_trusted_vault_key_name);
} }
VISIT_PROTO_FIELDS(const sync_pb::NigoriLocalData& proto) { VISIT_PROTO_FIELDS(const sync_pb::NigoriLocalData& proto) {
......
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