blob: b6a1537413248c2269aaf1f0a6182a390977915d [file] [log] [blame] [edit]
// 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 "arc/keymint/keymint_server.h"
#include <utility>
#include <base/check.h>
#include <base/functional/bind.h>
#include <base/task/single_thread_task_runner.h>
#include <base/threading/platform_thread.h>
#include <keymaster/android_keymaster_messages.h>
#include <mojo/keymint.mojom.h>
// The implementations of |arc::mojom::KeyMintServer| methods below have the
// following overall pattern:
//
// * Generate an std::unique_ptr to a KeyMint request data structure from the
// arguments received from Mojo, usually through the helpers in conversion.h.
//
// * Execute the operation in |backend->keymint()|, posting this task to a
// background thread. This produces a KeyMint 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 KeyMint response to the Mojo return values, and run the
// result callback.
//
namespace arc::keymint {
namespace {
constexpr size_t kOperationTableSize = 16;
// TODO(b/278968783): Add version negotiation for KeyMint.
// KeyMint Message versions are drawn from Android
// Keymaster Messages.
constexpr int32_t kKeyMintMessageVersion = 4;
} // namespace
KeyMintServer::Backend::Backend()
: context_(new context::ArcKeyMintContext()),
keymint_(context_, kOperationTableSize, kKeyMintMessageVersion) {}
KeyMintServer::Backend::~Backend() = default;
KeyMintServer::KeyMintServer()
: backend_thread_("BackendKeyMintThread"), weak_ptr_factory_(this) {
CHECK(backend_thread_.Start()) << "Failed to start keymint thread";
}
KeyMintServer::~KeyMintServer() = default;
void KeyMintServer::SetSystemVersion(uint32_t android_version,
uint32_t android_patchlevel) {
auto task_lambda = [](context::ArcKeyMintContext* context,
uint32_t android_version, uint32_t android_patchlevel) {
// |context| is guaranteed valid here because it's owned
// by |backend_|, which outlives the |backend_thread_|
// this runs on.
context->SetSystemVersion(android_version, android_patchlevel);
};
backend_thread_.task_runner()->PostTask(
FROM_HERE, base::BindOnce(task_lambda, backend_.context(),
android_version, android_patchlevel));
}
template <typename KmMember, typename KmRequest, typename KmResponse>
void KeyMintServer::RunKeyMintRequest(
const base::Location& location,
KmMember member,
std::unique_ptr<KmRequest> request,
base::OnceCallback<void(std::unique_ptr<KmResponse>)> callback) {
auto task_lambda =
[](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 KeyMint response data structure.
auto response =
std::make_unique<KmResponse>(keymaster->message_version());
// 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)));
};
// Post the KeyMint operation to a background thread while capturing the
// current task runner.
backend_thread_.task_runner()->PostTask(
location,
base::BindOnce(task_lambda, location,
base::SingleThreadTaskRunner::GetCurrentDefault(),
backend_.keymint(), member, std::move(request),
std::move(callback)));
}
void KeyMintServer::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>(
backend_.keymint()->message_version());
km_request->SetKeyMaterial(key_blob.data(), key_blob.size());
// Call keymint.
RunKeyMintRequest(
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 KeyMintServer::DeleteAllKeys(DeleteAllKeysCallback callback) {
// Prepare keymint request.
auto km_request = std::make_unique<::keymaster::DeleteAllKeysRequest>(
backend_.keymint()->message_version());
// Call keymint.
RunKeyMintRequest(
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)));
}
} // namespace arc::keymint