| // 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 |