blob: b7a7ca8a4220d3453d26b43910e075efb16e4e1d [file] [log] [blame]
// 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/conversion.h"
#include <utility>
namespace arc {
namespace keymaster {
namespace {
keymaster_key_format_t ConvertEnum(arc::mojom::KeyFormat key_format) {
return static_cast<keymaster_key_format_t>(key_format);
}
keymaster_purpose_t ConvertEnum(arc::mojom::KeyPurpose key_purpose) {
return static_cast<keymaster_purpose_t>(key_purpose);
}
keymaster_tag_t ConvertEnum(uint32_t tag) {
return static_cast<keymaster_tag_t>(tag);
}
class KmParamSet {
public:
explicit KmParamSet(const std::vector<arc::mojom::KeyParameterPtr>& data) {
param_set_.params = new keymaster_key_param_t[data.size()];
param_set_.length = data.size();
for (size_t i = 0; i < data.size(); ++i) {
keymaster_tag_t tag = ConvertEnum(data[i]->tag);
switch (keymaster_tag_get_type(tag)) {
case KM_ENUM:
case KM_ENUM_REP:
if (data[i]->param->is_integer()) {
param_set_.params[i] =
keymaster_param_enum(tag, data[i]->param->get_integer());
} else {
param_set_.params[i].tag = KM_TAG_INVALID;
}
break;
case KM_UINT:
case KM_UINT_REP:
if (data[i]->param->is_integer()) {
param_set_.params[i] =
keymaster_param_int(tag, data[i]->param->get_integer());
} else {
param_set_.params[i].tag = KM_TAG_INVALID;
}
break;
case KM_ULONG:
case KM_ULONG_REP:
if (data[i]->param->is_long_integer()) {
param_set_.params[i] =
keymaster_param_long(tag, data[i]->param->get_long_integer());
} else {
param_set_.params[i].tag = KM_TAG_INVALID;
}
break;
case KM_DATE:
if (data[i]->param->is_date_time()) {
param_set_.params[i] =
keymaster_param_date(tag, data[i]->param->get_date_time());
} else {
param_set_.params[i].tag = KM_TAG_INVALID;
}
break;
case KM_BOOL:
if (data[i]->param->is_boolean_value() &&
data[i]->param->get_boolean_value()) {
param_set_.params[i] = keymaster_param_bool(tag);
} else {
param_set_.params[i].tag = KM_TAG_INVALID;
}
break;
case KM_BIGNUM:
case KM_BYTES:
if (data[i]->param->is_blob()) {
param_set_.params[i] =
keymaster_param_blob(tag, data[i]->param->get_blob().data(),
data[i]->param->get_blob().size());
} else {
param_set_.params[i].tag = KM_TAG_INVALID;
}
break;
case KM_INVALID:
default:
param_set_.params[i].tag = KM_TAG_INVALID;
/* just skip */
break;
}
}
}
KmParamSet(KmParamSet&& other)
: param_set_{other.param_set_.params, other.param_set_.length} {
other.param_set_.length = 0;
other.param_set_.params = nullptr;
}
KmParamSet(const KmParamSet&) = delete;
KmParamSet& operator=(const KmParamSet&) = delete;
~KmParamSet() { delete[] param_set_.params; }
inline const keymaster_key_param_set_t& param_set() const {
return param_set_;
}
private:
keymaster_key_param_set_t param_set_;
};
} // namespace
std::unique_ptr<::keymaster::GetKeyCharacteristicsRequest>
MakeGetKeyCharacteristicsRequest(
const ::arc::mojom::GetKeyCharacteristicsRequestPtr& value) {
auto out = std::make_unique<::keymaster::GetKeyCharacteristicsRequest>();
out->SetKeyMaterial(value->key_blob.data(), value->key_blob.size());
ConvertToMessage(value->client_id, value->app_data, &out->additional_params);
return out;
}
std::unique_ptr<::keymaster::GenerateKeyRequest> MakeGenerateKeyRequest(
const std::vector<arc::mojom::KeyParameterPtr>& data) {
auto out = std::make_unique<::keymaster::GenerateKeyRequest>();
ConvertToMessage(data, &out->key_description);
return out;
}
std::unique_ptr<::keymaster::ImportKeyRequest> MakeImportKeyRequest(
const arc::mojom::ImportKeyRequestPtr& request) {
auto out = std::make_unique<::keymaster::ImportKeyRequest>();
ConvertToMessage(request->key_description, &out->key_description);
out->key_format = ConvertEnum(request->key_format);
out->SetKeyMaterial(request->key_data.data(), request->key_data.size());
return out;
}
std::unique_ptr<::keymaster::ExportKeyRequest> MakeExportKeyRequest(
const arc::mojom::ExportKeyRequestPtr& request) {
auto out = std::make_unique<::keymaster::ExportKeyRequest>();
out->key_format = ConvertEnum(request->key_format);
ConvertToMessage(request->client_id, request->app_data,
&out->additional_params);
out->SetKeyMaterial(request->key_blob.data(), request->key_blob.size());
return out;
}
std::unique_ptr<::keymaster::AttestKeyRequest> MakeAttestKeyRequest(
const arc::mojom::AttestKeyRequestPtr& request) {
auto out = std::make_unique<::keymaster::AttestKeyRequest>();
ConvertToMessage(request->attest_params, &out->attest_params);
out->SetKeyMaterial(request->key_to_attest.data(),
request->key_to_attest.size());
return out;
}
std::unique_ptr<::keymaster::UpgradeKeyRequest> MakeUpgradeKeyRequest(
const arc::mojom::UpgradeKeyRequestPtr& request) {
auto out = std::make_unique<::keymaster::UpgradeKeyRequest>();
ConvertToMessage(request->upgrade_params, &out->upgrade_params);
out->SetKeyMaterial(request->key_blob_to_upgrade.data(),
request->key_blob_to_upgrade.size());
return out;
}
std::unique_ptr<::keymaster::BeginOperationRequest> MakeBeginOperationRequest(
const arc::mojom::BeginRequestPtr& request) {
auto out = std::make_unique<::keymaster::BeginOperationRequest>();
out->purpose = ConvertEnum(request->purpose);
out->SetKeyMaterial(request->key.data(), request->key.size());
ConvertToMessage(request->in_params, &out->additional_params);
return out;
}
std::unique_ptr<::keymaster::UpdateOperationRequest> MakeUpdateOperationRequest(
const arc::mojom::UpdateRequestPtr& request) {
auto out = std::make_unique<::keymaster::UpdateOperationRequest>();
out->op_handle = request->op_handle;
ConvertToMessage(request->input, &out->input);
ConvertToMessage(request->in_params, &out->additional_params);
return out;
}
std::unique_ptr<::keymaster::FinishOperationRequest> MakeFinishOperationRequest(
const arc::mojom::FinishRequestPtr& request) {
auto out = std::make_unique<::keymaster::FinishOperationRequest>();
out->op_handle = request->op_handle;
ConvertToMessage(request->input, &out->input);
ConvertToMessage(request->signature, &out->signature);
ConvertToMessage(request->in_params, &out->additional_params);
return out;
}
arc::mojom::GetKeyCharacteristicsResultPtr MakeGetKeyCharacteristicsResult(
const ::keymaster::GetKeyCharacteristicsResponse& km_response) {
if (km_response.error == KM_ERROR_OK) {
return arc::mojom::GetKeyCharacteristicsResult::New(
arc::mojom::KeyCharacteristics::New(
ConvertToMojo(km_response.unenforced),
ConvertToMojo(km_response.enforced)),
km_response.error);
}
return arc::mojom::GetKeyCharacteristicsResult::New(
arc::mojom::KeyCharacteristics::New(), km_response.error);
}
arc::mojom::GenerateKeyResultPtr MakeGenerateKeyResult(
const ::keymaster::GenerateKeyResponse& km_response) {
if (km_response.error == KM_ERROR_OK) {
return arc::mojom::GenerateKeyResult::New(
ConvertToMojo(km_response.key_blob.key_material,
km_response.key_blob.key_material_size),
arc::mojom::KeyCharacteristics::New(
ConvertToMojo(km_response.unenforced),
ConvertToMojo(km_response.enforced)),
km_response.error);
}
return arc::mojom::GenerateKeyResult::New(
std::vector<uint8_t>(), arc::mojom::KeyCharacteristics::New(),
km_response.error);
}
arc::mojom::ImportKeyResultPtr MakeImportKeyResult(
const ::keymaster::ImportKeyResponse& km_response) {
if (km_response.error == KM_ERROR_OK) {
return arc::mojom::ImportKeyResult::New(
ConvertToMojo(km_response.key_blob.key_material,
km_response.key_blob.key_material_size),
arc::mojom::KeyCharacteristics::New(
ConvertToMojo(km_response.unenforced),
ConvertToMojo(km_response.enforced)),
km_response.error);
}
return arc::mojom::ImportKeyResult::New(std::vector<uint8_t>(),
arc::mojom::KeyCharacteristics::New(),
km_response.error);
}
arc::mojom::ExportKeyResultPtr MakeExportKeyResult(
const ::keymaster::ExportKeyResponse& km_response) {
if (km_response.error == KM_ERROR_OK) {
return arc::mojom::ExportKeyResult::New(
ConvertToMojo(km_response.key_data, km_response.key_data_length),
km_response.error);
}
return arc::mojom::ExportKeyResult::New(std::vector<uint8_t>(),
km_response.error);
}
arc::mojom::AttestKeyResultPtr MakeAttestKeyResult(
const ::keymaster::AttestKeyResponse& km_response) {
if (km_response.error == KM_ERROR_OK) {
return arc::mojom::AttestKeyResult::New(
ConvertToMojo(km_response.certificate_chain), km_response.error);
}
return arc::mojom::AttestKeyResult::New(std::vector<std::vector<uint8_t>>(),
km_response.error);
}
arc::mojom::UpgradeKeyResultPtr MakeUpgradeKeyResult(
const ::keymaster::UpgradeKeyResponse& km_response) {
if (km_response.error == KM_ERROR_OK) {
return arc::mojom::UpgradeKeyResult::New(
ConvertToMojo(km_response.upgraded_key.key_material,
km_response.upgraded_key.key_material_size),
km_response.error);
}
return arc::mojom::UpgradeKeyResult::New(std::vector<uint8_t>(),
km_response.error);
}
arc::mojom::BeginResultPtr MakeBeginResult(
const ::keymaster::BeginOperationResponse& km_response) {
if (km_response.error == KM_ERROR_OK) {
return arc::mojom::BeginResult::New(
ConvertToMojo(km_response.output_params), km_response.op_handle,
km_response.error);
}
return arc::mojom::BeginResult::New(
std::vector<arc::mojom::KeyParameterPtr>(), km_response.op_handle,
km_response.error);
}
arc::mojom::UpdateResultPtr MakeUpdateResult(
const ::keymaster::UpdateOperationResponse& km_response) {
if (km_response.error == KM_ERROR_OK) {
return arc::mojom::UpdateResult::New(
km_response.input_consumed, ConvertToMojo(km_response.output_params),
ConvertToMojo(km_response.output.begin(),
km_response.output.available_read()),
km_response.error);
}
return arc::mojom::UpdateResult::New(
0, std::vector<arc::mojom::KeyParameterPtr>(), std::vector<uint8_t>(),
km_response.error);
}
arc::mojom::FinishResultPtr MakeFinishResult(
const ::keymaster::FinishOperationResponse& km_response) {
if (km_response.error == KM_ERROR_OK) {
return arc::mojom::FinishResult::New(
ConvertToMojo(km_response.output_params),
ConvertToMojo(km_response.output.begin(),
km_response.output.available_read()),
km_response.error);
}
return arc::mojom::FinishResult::New(
std::vector<arc::mojom::KeyParameterPtr>(), std::vector<uint8_t>(),
km_response.error);
}
std::vector<uint8_t> ConvertToMojo(const uint8_t* data, const size_t size) {
return std::vector<uint8_t>(data, data + size);
}
std::vector<std::vector<uint8_t>> ConvertToMojo(
const keymaster_cert_chain_t& cert) {
std::vector<std::vector<uint8_t>> out(cert.entry_count);
for (size_t i = 0; i < cert.entry_count; ++i) {
const auto& entry = cert.entries[i];
out[i] = ConvertToMojo(entry.data, entry.data_length);
}
return out;
}
std::vector<arc::mojom::KeyParameterPtr> ConvertToMojo(
const keymaster_key_param_set_t& param_set) {
if (param_set.length == 0 || !param_set.params)
return std::vector<arc::mojom::KeyParameterPtr>();
std::vector<arc::mojom::KeyParameterPtr> out(param_set.length);
keymaster_key_param_t* params = param_set.params;
for (size_t i = 0; i < param_set.length; ++i) {
keymaster_tag_t tag = params[i].tag;
arc::mojom::IntegerKeyParamPtr param = arc::mojom::IntegerKeyParam::New();
switch (keymaster_tag_get_type(tag)) {
case KM_ENUM:
case KM_ENUM_REP:
param->set_integer(params[i].enumerated);
break;
case KM_UINT:
case KM_UINT_REP:
param->set_integer(params[i].integer);
break;
case KM_ULONG:
case KM_ULONG_REP:
param->set_long_integer(params[i].long_integer);
break;
case KM_DATE:
param->set_date_time(params[i].date_time);
break;
case KM_BOOL:
param->set_boolean_value(params[i].boolean);
break;
case KM_BIGNUM:
case KM_BYTES:
param->set_blob(
ConvertToMojo(params[i].blob.data, params[i].blob.data_length));
break;
case KM_INVALID:
tag = KM_TAG_INVALID;
/* just skip */
break;
}
out[i] = arc::mojom::KeyParameter::New(tag, std::move(param));
}
return out;
}
void ConvertToMessage(const std::vector<uint8_t>& data,
::keymaster::Buffer* out) {
out->Reinitialize(data.data(), data.size());
}
void ConvertToMessage(const std::vector<uint8_t>& clientId,
const std::vector<uint8_t>& appData,
::keymaster::AuthorizationSet* params) {
params->Clear();
if (!clientId.empty()) {
params->push_back(::keymaster::TAG_APPLICATION_ID, clientId.data(),
clientId.size());
}
if (!appData.empty()) {
params->push_back(::keymaster::TAG_APPLICATION_DATA, appData.data(),
appData.size());
}
}
void ConvertToMessage(const std::vector<arc::mojom::KeyParameterPtr>& data,
::keymaster::AuthorizationSet* out) {
KmParamSet param_set(data);
out->Reinitialize(param_set.param_set());
}
} // namespace keymaster
} // namespace arc