| // Copyright 2023 The ChromiumOS Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <libarc-attestation/lib/manager.h> |
| |
| #include <memory> |
| #include <utility> |
| #include <vector> |
| |
| #include <base/synchronization/waitable_event.h> |
| #include <base/threading/thread.h> |
| |
| #include <libarc-attestation/lib/provisioner.h> |
| #include <libarc-attestation/lib/version_attester.h> |
| |
| namespace arc_attestation { |
| |
| namespace { |
| |
| void RunInTaskRunnerBlocking(scoped_refptr<base::SingleThreadTaskRunner> runner, |
| base::OnceClosure task) { |
| base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, |
| base::WaitableEvent::InitialState::NOT_SIGNALED); |
| runner->PostTask( |
| FROM_HERE, std::move(task).Then(base::BindOnce( |
| &base::WaitableEvent::Signal, base::Unretained(&event)))); |
| event.Wait(); |
| } |
| |
| } // namespace |
| |
| ArcAttestationManager::ArcAttestationManager() {} |
| |
| void ArcAttestationManager::Setup() { |
| // Start the library thread. |
| library_thread_ = std::make_unique<base::Thread>("libarc-attestation-worker"); |
| base::Thread::Options options; |
| options.message_pump_type = base::MessagePumpType::IO; |
| library_thread_->StartWithOptions(std::move(options)); |
| library_task_runner_ = library_thread_->task_runner(); |
| |
| // Setup the provisioner. |
| provisioner_ = std::make_unique<Provisioner>(library_task_runner_); |
| version_attester_ = std::make_unique<VersionAttester>(provisioner_.get()); |
| } |
| |
| AndroidStatus ArcAttestationManager::ProvisionDkCert(bool blocking) { |
| // Quick check on if it's already provisioned. |
| if (provisioner_->is_provisioned()) |
| return AndroidStatus::ok(); |
| if (!blocking) { |
| // If we're not provisioned yet then we should not proceed to provisioning |
| // here because this call should be no blocking. |
| // TODO(b/275067764): We should trigger the retry mechanism in the |
| // background. |
| return AndroidStatus::from_keymint_code( |
| AndroidStatus::KeymintSpecificErrorCode:: |
| SECURE_HW_COMMUNICATION_FAILED); |
| } |
| AndroidStatus result; |
| RunInTaskRunnerBlocking( |
| library_task_runner_.get(), |
| base::BindOnce( |
| [](ArcAttestationManager* manager, AndroidStatus* result) { |
| *result = manager->provisioner_->ProvisionCert(); |
| }, |
| this, &result)); |
| return result; |
| } |
| |
| AndroidStatus ArcAttestationManager::GetDkCertChain( |
| std::vector<brillo::Blob>& cert_out) { |
| AndroidStatus result; |
| RunInTaskRunnerBlocking( |
| library_task_runner_.get(), |
| base::BindOnce( |
| [](ArcAttestationManager* manager, AndroidStatus* result, |
| std::vector<brillo::Blob>* cert_out) { |
| *result = manager->provisioner_->GetDkCertChain(*cert_out); |
| }, |
| this, &result, &cert_out)); |
| return result; |
| } |
| |
| // Sign with the device key. |
| AndroidStatus ArcAttestationManager::SignWithP256Dk(const brillo::Blob& input, |
| brillo::Blob& signature) { |
| AndroidStatus result; |
| RunInTaskRunnerBlocking( |
| library_task_runner_.get(), |
| base::BindOnce( |
| [](ArcAttestationManager* manager, AndroidStatus* result, |
| const brillo::Blob& input, brillo::Blob* signature) { |
| *result = manager->provisioner_->SignWithP256Dk(input, *signature); |
| }, |
| this, &result, input, &signature)); |
| return result; |
| } |
| |
| // Quote the ChromeOS specific blob for ARC Attestation. |
| AndroidStatus ArcAttestationManager::QuoteCrOSBlob( |
| const brillo::Blob& challenge, brillo::Blob& output) { |
| AndroidStatus result; |
| RunInTaskRunnerBlocking( |
| library_task_runner_.get(), |
| base::BindOnce( |
| [](ArcAttestationManager* manager, AndroidStatus* result, |
| const brillo::Blob& challenge, brillo::Blob* output) { |
| *result = |
| manager->version_attester_->QuoteCrOSBlob(challenge, *output); |
| }, |
| this, &result, challenge, &output)); |
| return result; |
| } |
| |
| } // namespace arc_attestation |