| // 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/ash/attestation/tpm_challenge_key.h" | 
 |  | 
 | #include <memory> | 
 | #include <string> | 
 | #include <utility> | 
 |  | 
 | #include "base/bind.h" | 
 | #include "base/memory/weak_ptr.h" | 
 | #include "base/sequence_checker.h" | 
 | #include "chrome/browser/ash/attestation/tpm_challenge_key_result.h" | 
 | #include "chrome/browser/ash/attestation/tpm_challenge_key_subtle.h" | 
 | #include "chrome/common/pref_names.h" | 
 | #include "chromeos/dbus/constants/attestation_constants.h" | 
 | #include "components/pref_registry/pref_registry_syncable.h" | 
 |  | 
 | class Profile; | 
 | class AttestationFlow; | 
 |  | 
 | namespace ash { | 
 | 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, | 
 |     MachineCertificateUploader* certificate_uploader_for_testing) { | 
 |   tpm_challenge_key_subtle_ = std::make_unique<TpmChallengeKeySubtleImpl>( | 
 |       attestation_flow_for_testing, certificate_uploader_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) { | 
 |   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| should not be empty. | 
 |   DCHECK((key_type != KEY_DEVICE) || (register_key == !key_name.empty())) | 
 |       << "Invalid arguments: " << register_key << " " << !key_name.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, /*will_register_key=*/register_key_, key_name, profile, | 
 |       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_, 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 ash |