| // Copyright 2019 The Chromium OS 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 "arc/keymaster/keymaster_server.h" |
| |
| #include <utility> |
| |
| #include <base/bind.h> |
| #include <base/threading/platform_thread.h> |
| #include <base/threading/thread_task_runner_handle.h> |
| #include <keymaster/android_keymaster_messages.h> |
| |
| #include "arc/keymaster/conversion.h" |
| |
| // The implementations of |arc::mojom::KeymasterServer| methods below have the |
| // following overall pattern: |
| // |
| // * Generate an std::unique_ptr to a Keymaster request data structure from the |
| // arguments received from Mojo, usually through the helpers in conversion.h. |
| // |
| // * Execute the operation in |backend->keymaster()|, posting this task to a |
| // background thread. This produces a Keymaster response data structure. |
| // |
| // * Post the response to a callback that runs on the original thread (in this |
| // case, the Mojo thread where the request started). |
| // |
| // * Convert the Keymaster response to the Mojo return values, and run the |
| // result callback. |
| // |
| namespace arc { |
| namespace keymaster { |
| |
| namespace { |
| |
| constexpr size_t kOperationTableSize = 16; |
| |
| } // namespace |
| |
| KeymasterServer::Backend::Backend() |
| : context_(new context::ArcKeymasterContext()), |
| keymaster_(context_, kOperationTableSize) {} |
| |
| KeymasterServer::Backend::~Backend() = default; |
| |
| KeymasterServer::KeymasterServer() : backend_thread_("BackendKeymasterThread") { |
| CHECK(backend_thread_.Start()) << "Failed to start keymaster thread"; |
| } |
| |
| KeymasterServer::~KeymasterServer() = default; |
| |
| void KeymasterServer::SetSystemVersion(uint32_t os_version, |
| uint32_t os_patchlevel) { |
| backend_thread_.task_runner()->PostTask( |
| FROM_HERE, base::BindOnce( |
| [](context::ArcKeymasterContext* context, |
| uint32_t os_version, uint32_t os_patchlevel) { |
| // |context| is guaranteed valid here because it's owned |
| // by |backend_|, which outlives the |backend_thread_| |
| // this runs on. |
| context->SetSystemVersion(os_version, os_patchlevel); |
| }, |
| backend_.context(), os_version, os_patchlevel)); |
| } |
| |
| template <typename KmMember, typename KmRequest, typename KmResponse> |
| void KeymasterServer::RunKeymasterRequest( |
| const base::Location& location, |
| KmMember member, |
| std::unique_ptr<KmRequest> request, |
| base::OnceCallback<void(std::unique_ptr<KmResponse>)> callback) { |
| // Post the Keymaster operation to a background thread while capturing the |
| // current task runner. |
| backend_thread_.task_runner()->PostTask( |
| location, |
| base::BindOnce( |
| [](const base::Location& location, |
| scoped_refptr<base::TaskRunner> original_task_runner, |
| ::keymaster::AndroidKeymaster* keymaster, KmMember member, |
| std::unique_ptr<KmRequest> request, |
| base::OnceCallback<void(std::unique_ptr<KmResponse>)> callback) { |
| // Prepare a Keymaster response data structure. |
| auto response = std::make_unique<KmResponse>(); |
| // Execute the operation. |
| (*keymaster.*member)(*request, response.get()); |
| // Post |callback| to the |original_task_runner| given |response|. |
| original_task_runner->PostTask( |
| location, |
| base::BindOnce(std::move(callback), std::move(response))); |
| }, |
| location, base::ThreadTaskRunnerHandle::Get(), backend_.keymaster(), |
| member, std::move(request), std::move(callback))); |
| } |
| |
| void KeymasterServer::AddRngEntropy(const std::vector<uint8_t>& data, |
| AddRngEntropyCallback callback) { |
| // Convert input |data| into |km_request|. All data is deep copied to avoid |
| // use-after-free. |
| auto km_request = std::make_unique<::keymaster::AddEntropyRequest>(); |
| ConvertToMessage(data, &km_request->random_data); |
| |
| // Call keymaster. |
| RunKeymasterRequest( |
| FROM_HERE, &::keymaster::AndroidKeymaster::AddRngEntropy, |
| std::move(km_request), |
| base::BindOnce( |
| [](AddRngEntropyCallback callback, |
| std::unique_ptr<::keymaster::AddEntropyResponse> km_response) { |
| // Run callback. |
| std::move(callback).Run(km_response->error); |
| }, |
| std::move(callback))); |
| } |
| |
| void KeymasterServer::GetKeyCharacteristics( |
| ::arc::mojom::GetKeyCharacteristicsRequestPtr request, |
| GetKeyCharacteristicsCallback callback) { |
| // Convert input |request| into |km_request|. All data is deep copied to avoid |
| // use-after-free. |
| auto km_request = MakeGetKeyCharacteristicsRequest(request); |
| |
| // Call keymaster. |
| RunKeymasterRequest( |
| FROM_HERE, &::keymaster::AndroidKeymaster::GetKeyCharacteristics, |
| std::move(km_request), |
| base::BindOnce( |
| [](GetKeyCharacteristicsCallback callback, |
| std::unique_ptr<::keymaster::GetKeyCharacteristicsResponse> |
| km_response) { |
| // Prepare mojo response. |
| auto response = MakeGetKeyCharacteristicsResult(*km_response); |
| // Run callback. |
| std::move(callback).Run(std::move(response)); |
| }, |
| std::move(callback))); |
| } |
| |
| void KeymasterServer::GenerateKey( |
| std::vector<mojom::KeyParameterPtr> key_params, |
| GenerateKeyCallback callback) { |
| // Convert input |key_params| into |km_request|. All data is deep copied to |
| // avoid use-after-free. |
| auto km_request = MakeGenerateKeyRequest(key_params); |
| |
| // Call keymaster. |
| RunKeymasterRequest( |
| FROM_HERE, &::keymaster::AndroidKeymaster::GenerateKey, |
| std::move(km_request), |
| base::BindOnce( |
| [](GenerateKeyCallback callback, |
| std::unique_ptr<::keymaster::GenerateKeyResponse> km_response) { |
| // Prepare mojo response. |
| auto response = MakeGenerateKeyResult(*km_response); |
| // Run callback. |
| std::move(callback).Run(std::move(response)); |
| }, |
| std::move(callback))); |
| } |
| |
| void KeymasterServer::ImportKey(arc::mojom::ImportKeyRequestPtr request, |
| ImportKeyCallback callback) { |
| // Convert input |request| into |km_request|. All data is deep copied to avoid |
| // use-after-free. |
| auto km_request = MakeImportKeyRequest(request); |
| |
| // Call keymaster. |
| RunKeymasterRequest( |
| FROM_HERE, &::keymaster::AndroidKeymaster::ImportKey, |
| std::move(km_request), |
| base::BindOnce( |
| [](ImportKeyCallback callback, |
| std::unique_ptr<::keymaster::ImportKeyResponse> km_response) { |
| // Prepare mojo response. |
| auto response = MakeImportKeyResult(*km_response); |
| // Run callback. |
| std::move(callback).Run(std::move(response)); |
| }, |
| std::move(callback))); |
| } |
| |
| void KeymasterServer::ExportKey(arc::mojom::ExportKeyRequestPtr request, |
| ExportKeyCallback callback) { |
| // Convert input |request| into |km_request|. All data is deep copied to avoid |
| // use-after-free. |
| auto km_request = MakeExportKeyRequest(request); |
| |
| // Call keymaster. |
| RunKeymasterRequest( |
| FROM_HERE, &::keymaster::AndroidKeymaster::ExportKey, |
| std::move(km_request), |
| base::BindOnce( |
| [](ExportKeyCallback callback, |
| std::unique_ptr<::keymaster::ExportKeyResponse> km_response) { |
| // Prepare mojo response. |
| auto response = MakeExportKeyResult(*km_response); |
| // Run callback. |
| std::move(callback).Run(std::move(response)); |
| }, |
| std::move(callback))); |
| } |
| |
| void KeymasterServer::AttestKey(arc::mojom::AttestKeyRequestPtr request, |
| AttestKeyCallback callback) { |
| // Convert input |request| into |km_request|. All data is deep copied to avoid |
| // use-after-free. |
| auto km_request = MakeAttestKeyRequest(request); |
| |
| // Call keymaster. |
| RunKeymasterRequest( |
| FROM_HERE, &::keymaster::AndroidKeymaster::AttestKey, |
| std::move(km_request), |
| base::BindOnce( |
| [](AttestKeyCallback callback, |
| std::unique_ptr<::keymaster::AttestKeyResponse> km_response) { |
| // Prepare mojo response. |
| auto response = MakeAttestKeyResult(*km_response); |
| // Run callback. |
| std::move(callback).Run(std::move(response)); |
| }, |
| std::move(callback))); |
| } |
| |
| void KeymasterServer::UpgradeKey(arc::mojom::UpgradeKeyRequestPtr request, |
| UpgradeKeyCallback callback) { |
| // Convert input |request| into |km_request|. All data is deep copied to avoid |
| // use-after-free. |
| auto km_request = MakeUpgradeKeyRequest(request); |
| |
| // Call keymaster. |
| RunKeymasterRequest( |
| FROM_HERE, &::keymaster::AndroidKeymaster::UpgradeKey, |
| std::move(km_request), |
| base::BindOnce( |
| [](UpgradeKeyCallback callback, |
| std::unique_ptr<::keymaster::UpgradeKeyResponse> km_response) { |
| // Prepare mojo response. |
| auto response = MakeUpgradeKeyResult(*km_response); |
| // Run callback. |
| std::move(callback).Run(std::move(response)); |
| }, |
| std::move(callback))); |
| } |
| |
| void KeymasterServer::DeleteKey(const std::vector<uint8_t>& key_blob, |
| DeleteKeyCallback callback) { |
| // Convert input |key_blob| into |km_request|. All data is deep copied to |
| // avoid use-after-free. |
| auto km_request = std::make_unique<::keymaster::DeleteKeyRequest>(); |
| km_request->SetKeyMaterial(key_blob.data(), key_blob.size()); |
| |
| // Call keymaster. |
| RunKeymasterRequest( |
| FROM_HERE, &::keymaster::AndroidKeymaster::DeleteKey, |
| std::move(km_request), |
| base::BindOnce( |
| [](DeleteKeyCallback callback, |
| std::unique_ptr<::keymaster::DeleteKeyResponse> km_response) { |
| // Run callback. |
| std::move(callback).Run(km_response->error); |
| }, |
| std::move(callback))); |
| } |
| |
| void KeymasterServer::DeleteAllKeys(DeleteAllKeysCallback callback) { |
| // Prepare keymaster request. |
| auto km_request = std::make_unique<::keymaster::DeleteAllKeysRequest>(); |
| |
| // Call keymaster. |
| RunKeymasterRequest( |
| FROM_HERE, &::keymaster::AndroidKeymaster::DeleteAllKeys, |
| std::move(km_request), |
| base::BindOnce( |
| [](DeleteAllKeysCallback callback, |
| std::unique_ptr<::keymaster::DeleteAllKeysResponse> km_response) { |
| // Run callback. |
| std::move(callback).Run(km_response->error); |
| }, |
| std::move(callback))); |
| } |
| |
| void KeymasterServer::Begin(arc::mojom::BeginRequestPtr request, |
| BeginCallback callback) { |
| // Convert input |request| into |km_request|. All data is deep copied to avoid |
| // use-after-free. |
| auto km_request = MakeBeginOperationRequest(request); |
| |
| // Call keymaster. |
| RunKeymasterRequest( |
| FROM_HERE, &::keymaster::AndroidKeymaster::BeginOperation, |
| std::move(km_request), |
| base::BindOnce( |
| [](BeginCallback callback, |
| std::unique_ptr<::keymaster::BeginOperationResponse> km_response) { |
| // Prepare mojo response. |
| auto response = MakeBeginResult(*km_response); |
| // Run callback. |
| std::move(callback).Run(std::move(response)); |
| }, |
| std::move(callback))); |
| } |
| |
| void KeymasterServer::Update(arc::mojom::UpdateRequestPtr request, |
| UpdateCallback callback) { |
| // Convert input |request| into |km_request|. All data is deep copied to avoid |
| // use-after-free. |
| auto km_request = MakeUpdateOperationRequest(request); |
| |
| // Call keymaster. |
| RunKeymasterRequest( |
| FROM_HERE, &::keymaster::AndroidKeymaster::UpdateOperation, |
| std::move(km_request), |
| base::BindOnce( |
| [](UpdateCallback callback, |
| std::unique_ptr<::keymaster::UpdateOperationResponse> |
| km_response) { |
| // Prepare mojo response. |
| auto response = MakeUpdateResult(*km_response); |
| // Run callback. |
| std::move(callback).Run(std::move(response)); |
| }, |
| std::move(callback))); |
| } |
| |
| void KeymasterServer::Finish(arc::mojom::FinishRequestPtr request, |
| FinishCallback callback) { |
| // Convert input |request| into |km_request|. All data is deep copied to avoid |
| // use-after-free. |
| auto km_request = MakeFinishOperationRequest(request); |
| |
| // Call keymaster. |
| RunKeymasterRequest( |
| FROM_HERE, &::keymaster::AndroidKeymaster::FinishOperation, |
| std::move(km_request), |
| base::BindOnce( |
| [](FinishCallback callback, |
| std::unique_ptr<::keymaster::FinishOperationResponse> |
| km_response) { |
| // Prepare mojo response. |
| auto response = MakeFinishResult(*km_response); |
| // Run callback. |
| std::move(callback).Run(std::move(response)); |
| }, |
| std::move(callback))); |
| } |
| |
| void KeymasterServer::Abort(uint64_t op_handle, AbortCallback callback) { |
| // Prepare keymaster request. |
| auto km_request = std::make_unique<::keymaster::AbortOperationRequest>(); |
| km_request->op_handle = op_handle; |
| |
| // Call keymaster. |
| RunKeymasterRequest( |
| FROM_HERE, &::keymaster::AndroidKeymaster::AbortOperation, |
| std::move(km_request), |
| base::BindOnce( |
| [](AbortCallback callback, |
| std::unique_ptr<::keymaster::AbortOperationResponse> km_response) { |
| // Run callback. |
| std::move(callback).Run(km_response->error); |
| }, |
| std::move(callback))); |
| } |
| |
| } // namespace keymaster |
| } // namespace arc |