blob: e53ce017d663847b5925e3adcc5384d00b59bd9b [file] [log] [blame]
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/sync/nigori/pending_local_nigori_commit.h"
#include <utility>
#include "base/logging.h"
#include "base/metrics/histogram_functions.h"
#include "base/time/time.h"
#include "components/sync/engine/nigori/cross_user_sharing_public_key.h"
#include "components/sync/engine/nigori/cross_user_sharing_public_private_key_pair.h"
#include "components/sync/engine/nigori/key_derivation_params.h"
#include "components/sync/engine/nigori/nigori.h"
#include "components/sync/nigori/cryptographer_impl.h"
#include "components/sync/nigori/keystore_keys_cryptographer.h"
#include "components/sync/nigori/nigori_state.h"
#include "components/sync/protocol/nigori_specifics.pb.h"
namespace syncer {
namespace {
using sync_pb::NigoriSpecifics;
// Populates a new key pair with a version 0 to `state`, or replaces the
// existing key pair with the current key version. This method does not affect
// key pairs with other versions.
void InitNewOrFixCorruptedKeyPair(
const CrossUserSharingPublicPrivateKeyPair& cross_user_sharing_key_pair,
NigoriState* state) {
CHECK(state->NeedsGenerateCrossUserSharingKeyPair());
// Keep the existing version in case if the key pair is corrupted.
const uint32_t version =
state->cross_user_sharing_key_pair_version.value_or(0);
state->cross_user_sharing_public_key =
CrossUserSharingPublicKey::CreateByImport(
cross_user_sharing_key_pair.GetRawPublicKey());
state->cross_user_sharing_key_pair_version = version;
std::optional<CrossUserSharingPublicPrivateKeyPair> key_pair =
CrossUserSharingPublicPrivateKeyPair::CreateByImport(
cross_user_sharing_key_pair.GetRawPrivateKey());
CHECK(key_pair.has_value());
state->cryptographer->SetKeyPair(std::move(key_pair.value()), version);
state->cryptographer->SelectDefaultCrossUserSharingKey(version);
}
class CustomPassphraseSetter : public PendingLocalNigoriCommit {
public:
explicit CustomPassphraseSetter(
const std::string& passphrase,
const KeyDerivationParams& key_derivation_params)
: passphrase_(passphrase),
key_derivation_params_(key_derivation_params) {}
CustomPassphraseSetter(const CustomPassphraseSetter&) = delete;
CustomPassphraseSetter& operator=(const CustomPassphraseSetter&) = delete;
~CustomPassphraseSetter() override = default;
bool TryApply(NigoriState* state) const override {
if (state->pending_keys.has_value()) {
return false;
}
switch (state->passphrase_type) {
case NigoriSpecifics::UNKNOWN:
return false;
case NigoriSpecifics::FROZEN_IMPLICIT_PASSPHRASE:
case NigoriSpecifics::CUSTOM_PASSPHRASE:
// Attempt to set the explicit passphrase when one was already set. It's
// possible if we received new NigoriSpecifics during the passphrase
// setup.
DVLOG(1)
<< "Attempt to set explicit passphrase failed, because one was "
"already set.";
return false;
case NigoriSpecifics::IMPLICIT_PASSPHRASE:
case NigoriSpecifics::KEYSTORE_PASSPHRASE:
case NigoriSpecifics::TRUSTED_VAULT_PASSPHRASE:
break;
}
const std::string default_key_name =
state->cryptographer->EmplaceKey(passphrase_, key_derivation_params_);
if (default_key_name.empty()) {
DLOG(ERROR) << "Failed to set encryption passphrase";
return false;
}
state->cryptographer->SelectDefaultEncryptionKey(default_key_name);
state->pending_keystore_decryptor_token.reset();
state->passphrase_type = NigoriSpecifics::CUSTOM_PASSPHRASE;
state->custom_passphrase_key_derivation_params = key_derivation_params_;
state->encrypt_everything = true;
state->custom_passphrase_time = base::Time::Now();
return true;
}
void OnSuccess(const NigoriState& state,
SyncEncryptionHandler::Observer* observer) override {
DCHECK(!state.pending_keys.has_value());
observer->OnPassphraseTypeChanged(PassphraseType::kCustomPassphrase,
state.custom_passphrase_time);
observer->OnCryptographerStateChanged(state.cryptographer.get(),
/*has_pending_keys=*/false);
observer->OnEncryptedTypesChanged(state.GetEncryptedTypes(),
/*encrypt_everything=*/true);
observer->OnPassphraseAccepted();
}
void OnFailure(SyncEncryptionHandler::Observer* observer) override {}
private:
const std::string passphrase_;
const KeyDerivationParams key_derivation_params_;
};
class KeystoreInitializer : public PendingLocalNigoriCommit {
public:
KeystoreInitializer() {
cross_user_sharing_public_private_key_pair_ =
CrossUserSharingPublicPrivateKeyPair::GenerateNewKeyPair();
}
KeystoreInitializer(const KeystoreInitializer&) = delete;
KeystoreInitializer& operator=(const KeystoreInitializer&) = delete;
~KeystoreInitializer() override = default;
bool TryApply(NigoriState* state) const override {
DCHECK(!state->keystore_keys_cryptographer->IsEmpty());
if (state->passphrase_type != NigoriSpecifics::UNKNOWN) {
return false;
}
std::unique_ptr<CryptographerImpl> cryptographer =
state->keystore_keys_cryptographer->ToCryptographerImpl();
DCHECK(!cryptographer->GetDefaultEncryptionKeyName().empty());
state->cryptographer->EmplaceAllNigoriKeysFrom(*cryptographer);
state->cryptographer->SelectDefaultEncryptionKey(
cryptographer->GetDefaultEncryptionKeyName());
state->passphrase_type = NigoriSpecifics::KEYSTORE_PASSPHRASE;
state->keystore_migration_time = base::Time::Now();
if (cross_user_sharing_public_private_key_pair_.has_value()) {
InitNewOrFixCorruptedKeyPair(
cross_user_sharing_public_private_key_pair_.value(), state);
}
return true;
}
void OnSuccess(const NigoriState& state,
SyncEncryptionHandler::Observer* observer) override {
// Note: `passphrase_time` isn't populated for keystore passphrase.
observer->OnPassphraseTypeChanged(PassphraseType::kKeystorePassphrase,
/*passphrase_time=*/base::Time());
observer->OnCryptographerStateChanged(state.cryptographer.get(),
/*has_pending_keys=*/false);
}
void OnFailure(SyncEncryptionHandler::Observer* observer) override {}
private:
std::optional<CrossUserSharingPublicPrivateKeyPair>
cross_user_sharing_public_private_key_pair_;
};
class KeystoreReencryptor : public PendingLocalNigoriCommit {
public:
KeystoreReencryptor() = default;
KeystoreReencryptor(const KeystoreReencryptor&) = delete;
KeystoreReencryptor& operator=(const KeystoreReencryptor&) = delete;
~KeystoreReencryptor() override = default;
bool TryApply(NigoriState* state) const override {
if (!state->NeedsKeystoreReencryption()) {
return false;
}
const std::string new_default_key_name = state->cryptographer->EmplaceKey(
state->keystore_keys_cryptographer->keystore_keys().back(),
KeyDerivationParams::CreateForPbkdf2());
state->cryptographer->SelectDefaultEncryptionKey(new_default_key_name);
return true;
}
void OnSuccess(const NigoriState& state,
SyncEncryptionHandler::Observer* observer) override {
observer->OnCryptographerStateChanged(state.cryptographer.get(),
/*has_pending_keys=*/false);
}
void OnFailure(SyncEncryptionHandler::Observer* observer) override {}
};
class CrossUserSharingPublicPrivateKeyInitializer
: public PendingLocalNigoriCommit {
public:
CrossUserSharingPublicPrivateKeyInitializer()
: cross_user_sharing_public_private_key_pair_(
CrossUserSharingPublicPrivateKeyPair::GenerateNewKeyPair()) {}
CrossUserSharingPublicPrivateKeyInitializer(
const CrossUserSharingPublicPrivateKeyInitializer&) = delete;
CrossUserSharingPublicPrivateKeyInitializer& operator=(
const CrossUserSharingPublicPrivateKeyInitializer&) = delete;
~CrossUserSharingPublicPrivateKeyInitializer() override = default;
bool TryApply(NigoriState* state) const override {
if (!state->NeedsGenerateCrossUserSharingKeyPair()) {
return false;
}
InitNewOrFixCorruptedKeyPair(cross_user_sharing_public_private_key_pair_,
state);
return true;
}
void OnSuccess(const NigoriState& state,
SyncEncryptionHandler::Observer* observer) override {
observer->OnCryptographerStateChanged(state.cryptographer.get(),
/*has_pending_keys=*/false);
}
void OnFailure(SyncEncryptionHandler::Observer* observer) override {}
private:
CrossUserSharingPublicPrivateKeyPair
cross_user_sharing_public_private_key_pair_;
};
} // namespace
// static
std::unique_ptr<PendingLocalNigoriCommit>
PendingLocalNigoriCommit::ForSetCustomPassphrase(
const std::string& passphrase,
const KeyDerivationParams& key_derivation_params) {
return std::make_unique<CustomPassphraseSetter>(passphrase,
key_derivation_params);
}
// static
std::unique_ptr<PendingLocalNigoriCommit>
PendingLocalNigoriCommit::ForKeystoreInitialization() {
return std::make_unique<KeystoreInitializer>();
}
// static
std::unique_ptr<PendingLocalNigoriCommit>
PendingLocalNigoriCommit::ForKeystoreReencryption() {
return std::make_unique<KeystoreReencryptor>();
}
// static
std::unique_ptr<PendingLocalNigoriCommit>
PendingLocalNigoriCommit::ForCrossUserSharingPublicPrivateKeyInitializer() {
return std::make_unique<CrossUserSharingPublicPrivateKeyInitializer>();
}
} // namespace syncer