blob: 61afe028beb335d088baf75327b0fbea8d95566e [file] [log] [blame]
// Copyright 2019 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 "chrome/browser/chromeos/attestation/tpm_challenge_key.h"
#include "base/base64.h"
#include "base/bind.h"
#include "base/check_op.h"
#include "base/compiler_specific.h"
#include "base/strings/stringprintf.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/attestation/attestation_ca_client.h"
#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chrome/browser/chromeos/settings/cros_settings.h"
#include "chrome/browser/extensions/chrome_extension_function_details.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "chromeos/cryptohome/async_method_caller.h"
#include "chromeos/cryptohome/cryptohome_parameters.h"
#include "chromeos/settings/cros_settings_names.h"
#include "chromeos/tpm/install_attributes.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_service.h"
namespace chromeos {
namespace attestation {
//========================= TpmChallengeKeyFactory =============================
TpmChallengeKey* TpmChallengeKeyFactory::next_result_for_testing_ = nullptr;
// static
std::unique_ptr<TpmChallengeKey> TpmChallengeKeyFactory::Create() {
if (UNLIKELY(next_result_for_testing_)) {
std::unique_ptr<TpmChallengeKey> result(next_result_for_testing_);
next_result_for_testing_ = nullptr;
return result;
}
return std::make_unique<TpmChallengeKeyImpl>();
}
// static
void TpmChallengeKeyFactory::SetForTesting(
std::unique_ptr<TpmChallengeKey> next_result) {
// unique_ptr itself cannot be stored in a static variable because of its
// complex destructor.
next_result_for_testing_ = next_result.release();
}
//=========================== TpmChallengeKeyImpl ==============================
void TpmChallengeKey::RegisterProfilePrefs(
user_prefs::PrefRegistrySyncable* registry) {
registry->RegisterBooleanPref(prefs::kAttestationEnabled, false);
}
TpmChallengeKeyImpl::TpmChallengeKeyImpl() {
tpm_challenge_key_subtle_ = TpmChallengeKeySubtleFactory::Create();
}
TpmChallengeKeyImpl::TpmChallengeKeyImpl(
AttestationFlow* attestation_flow_for_testing) {
tpm_challenge_key_subtle_ =
std::make_unique<TpmChallengeKeySubtleImpl>(attestation_flow_for_testing);
}
TpmChallengeKeyImpl::~TpmChallengeKeyImpl() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
void TpmChallengeKeyImpl::BuildResponse(AttestationKeyType key_type,
Profile* profile,
TpmChallengeKeyCallback callback,
const std::string& challenge,
bool register_key,
const std::string& key_name_for_spkac) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(callback_.is_null());
DCHECK(!callback.is_null());
// For device key: if |register_key| is true, |key_name_for_spkac| should not
// be empty; if |register_key| is false, |key_name_for_spkac| is not used.
DCHECK((key_type != KEY_DEVICE) ||
(register_key == !key_name_for_spkac.empty()))
<< "Invalid arguments: " << register_key << " "
<< !key_name_for_spkac.empty();
register_key_ = register_key;
challenge_ = challenge;
callback_ = std::move(callback);
// Empty |key_name| means that some default name will be used.
tpm_challenge_key_subtle_->StartPrepareKeyStep(
key_type, /*key_name=*/std::string(), profile, key_name_for_spkac,
base::BindOnce(&TpmChallengeKeyImpl::OnPrepareKeyDone,
weak_factory_.GetWeakPtr()));
}
void TpmChallengeKeyImpl::OnPrepareKeyDone(
const TpmChallengeKeyResult& prepare_key_result) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!prepare_key_result.IsSuccess()) {
std::move(callback_).Run(prepare_key_result);
return;
}
tpm_challenge_key_subtle_->StartSignChallengeStep(
challenge_, /*include_signed_public_key=*/register_key_,
base::BindOnce(&TpmChallengeKeyImpl::OnSignChallengeDone,
weak_factory_.GetWeakPtr()));
}
void TpmChallengeKeyImpl::OnSignChallengeDone(
const TpmChallengeKeyResult& sign_challenge_result) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!register_key_ || !sign_challenge_result.IsSuccess()) {
std::move(callback_).Run(sign_challenge_result);
return;
}
tpm_challenge_key_subtle_->StartRegisterKeyStep(
base::BindOnce(&TpmChallengeKeyImpl::OnRegisterKeyDone,
weak_factory_.GetWeakPtr(), sign_challenge_result));
}
void TpmChallengeKeyImpl::OnRegisterKeyDone(
const TpmChallengeKeyResult& challenge_response,
const TpmChallengeKeyResult& register_key_result) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// If StartRegisterKeyStep failed, |register_key_result| contains an error
// about it.
if (!register_key_result.IsSuccess()) {
std::move(callback_).Run(register_key_result);
return;
}
// All steps succeeded, return the final result. The challenge response that
// is expected from |BuildResponse| was received in |OnSignChallengeDone|, so
// return it now.
std::move(callback_).Run(challenge_response);
}
} // namespace attestation
} // namespace chromeos