| // 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 <array> |
| #include <memory> |
| #include <utility> |
| #include <vector> |
| |
| #include <gtest/gtest.h> |
| |
| #include "arc/keymaster/keymaster_logger.h" |
| |
| namespace arc { |
| namespace keymaster { |
| |
| namespace { |
| |
| KeymasterLogger logger; |
| |
| constexpr std::array<uint8_t, 3> kBlob1{{0, 42, 55}}; |
| constexpr std::array<uint8_t, 4> kBlob2{{251, 151, 101, 71}}; |
| constexpr std::array<uint8_t, 5> kBlob3{{1, 2, 3, 4, 5}}; |
| |
| ::testing::AssertionResult VerifyVectorUint8(const uint8_t* a, |
| const size_t a_size, |
| const std::vector<uint8_t>& b) { |
| if (a_size != b.size()) { |
| return ::testing::AssertionFailure() |
| << "Sizes differ: a=" << a_size << " b=" << b.size(); |
| } |
| for (size_t i = 0; i < a_size; ++i) { |
| if (a[i] != b[i]) { |
| return ::testing::AssertionFailure() |
| << "Elements differ: a=" << static_cast<int>(a[i]) |
| << " b=" << static_cast<int>(b[i]); |
| } |
| } |
| return ::testing::AssertionSuccess(); |
| } |
| |
| ::testing::AssertionResult VerifyKeyParameters( |
| const ::keymaster::AuthorizationSet& a, |
| const std::vector<arc::mojom::KeyParameterPtr>& b) { |
| if (a.size() != b.size()) { |
| return ::testing::AssertionFailure() |
| << "Sizes differ: a=" << a.size() << " b=" << b.size(); |
| } |
| |
| for (size_t i = 0; i < a.size(); ++i) { |
| if (a[i].tag != b[i]->tag) { |
| return ::testing::AssertionFailure() |
| << "Tags differ: i=" << i |
| << " a=" << static_cast<uint32_t>(a[i].tag) << " b=" << b[i]->tag; |
| } |
| } |
| if (!(b[0]->param->is_boolean_value() && b[1]->param->is_integer() && |
| b[2]->param->is_long_integer() && b[3]->param->is_date_time() && |
| b[4]->param->is_blob())) |
| return ::testing::AssertionFailure() << "Incorrect union value type"; |
| if (!(a[0].boolean == b[0]->param->get_boolean_value() && |
| a[1].integer == b[1]->param->get_integer() && |
| a[2].long_integer == b[2]->param->get_long_integer() && |
| a[3].date_time == b[3]->param->get_date_time())) |
| return ::testing::AssertionFailure() << "Values differ"; |
| return VerifyVectorUint8(a[4].blob.data, a[4].blob.data_length, |
| b[4]->param->get_blob()); |
| } |
| |
| std::vector<arc::mojom::KeyParameterPtr> KeyParameterVector() { |
| std::vector<arc::mojom::KeyParameterPtr> parameters(5); |
| // bool |
| auto paramBool = arc::mojom::IntegerKeyParam::New(); |
| paramBool->set_boolean_value(true); |
| parameters[0] = |
| arc::mojom::KeyParameter::New(KM_TAG_CALLER_NONCE, std::move(paramBool)); |
| // enum, enum_rep, int, int_rep |
| auto paramInt = arc::mojom::IntegerKeyParam::New(); |
| paramInt->set_integer(KM_ALGORITHM_TRIPLE_DES); |
| parameters[1] = |
| arc::mojom::KeyParameter::New(KM_TAG_ALGORITHM, std::move(paramInt)); |
| // long |
| auto paramLong = arc::mojom::IntegerKeyParam::New(); |
| paramLong->set_long_integer(65537); |
| parameters[2] = arc::mojom::KeyParameter::New(KM_TAG_RSA_PUBLIC_EXPONENT, |
| std::move(paramLong)); |
| // date |
| auto paramDate = arc::mojom::IntegerKeyParam::New(); |
| paramDate->set_date_time(1337); |
| parameters[3] = arc::mojom::KeyParameter::New(KM_TAG_ACTIVE_DATETIME, |
| std::move(paramDate)); |
| // bignum, bytes |
| auto paramBlob = arc::mojom::IntegerKeyParam::New(); |
| paramBlob->set_blob(std::vector<uint8_t>(kBlob1.begin(), kBlob1.end())); |
| parameters[4] = arc::mojom::KeyParameter::New(KM_TAG_APPLICATION_DATA, |
| std::move(paramBlob)); |
| return parameters; |
| } |
| |
| } // namespace |
| |
| TEST(ConvertToMojo, Uint8Vector) { |
| // Convert. |
| std::vector<uint8_t> output = ConvertToMojo(kBlob1.data(), kBlob1.size()); |
| |
| // Verify. |
| EXPECT_TRUE(VerifyVectorUint8(kBlob1.data(), kBlob1.size(), output)); |
| } |
| |
| TEST(ConvertToMojo, KeyParameterVector) { |
| // Prepare. |
| ::keymaster::AuthorizationSet input; |
| input.push_back(keymaster_param_bool(KM_TAG_CALLER_NONCE)); // bool |
| input.push_back(keymaster_param_enum( |
| KM_TAG_ALGORITHM, |
| KM_ALGORITHM_TRIPLE_DES)); // enum, enum_rep, int, int_rep |
| input.push_back( |
| keymaster_param_long(KM_TAG_RSA_PUBLIC_EXPONENT, 65537)); // long |
| input.push_back(keymaster_param_date(KM_TAG_ACTIVE_DATETIME, 1337)); // date |
| input.push_back(keymaster_param_blob(KM_TAG_APPLICATION_DATA, kBlob1.data(), |
| kBlob1.size())); // bignum, bytes |
| |
| // Convert. |
| std::vector<arc::mojom::KeyParameterPtr> output = ConvertToMojo(input); |
| |
| // Verify. |
| EXPECT_TRUE(VerifyKeyParameters(input, output)); |
| } |
| |
| TEST(ConvertToMessage, Buffer) { |
| // Prepare. |
| std::vector<uint8_t> input(kBlob1.begin(), kBlob1.end()); |
| |
| // Convert. |
| ::keymaster::Buffer buffer; |
| ConvertToMessage(input, &buffer); |
| uint8_t output[input.size()]; |
| |
| // Verify. |
| EXPECT_TRUE(buffer.read(output, input.size())); |
| EXPECT_TRUE(VerifyVectorUint8(output, input.size(), input)); |
| } |
| |
| TEST(ConvertToMessage, ReusedBuffer) { |
| // Prepare. |
| std::vector<uint8_t> input1(kBlob1.begin(), kBlob1.end()); |
| std::vector<uint8_t> input2(kBlob2.begin(), kBlob2.end()); |
| |
| // Convert. |
| ::keymaster::Buffer buffer; |
| ConvertToMessage(input1, &buffer); |
| ConvertToMessage(input2, &buffer); |
| uint8_t output[kBlob2.size()]; |
| |
| // Verify. |
| EXPECT_TRUE(buffer.read(output, kBlob2.size())); |
| EXPECT_TRUE(VerifyVectorUint8(output, kBlob2.size(), input2)); |
| } |
| |
| TEST(ConvertToMessage, ClientIdAndAppData) { |
| // Prepare. |
| std::vector<uint8_t> clientId(kBlob1.begin(), kBlob1.end()); |
| std::vector<uint8_t> appData(kBlob2.begin(), kBlob2.end()); |
| |
| // Convert. |
| ::keymaster::AuthorizationSet output; |
| ConvertToMessage(clientId, appData, &output); |
| |
| // Verify. |
| ASSERT_EQ(2, output.size()); |
| EXPECT_EQ(KM_TAG_APPLICATION_ID, output[0].tag); |
| EXPECT_EQ(KM_TAG_APPLICATION_DATA, output[1].tag); |
| EXPECT_TRUE(VerifyVectorUint8(output[0].blob.data, output[0].blob.data_length, |
| clientId)); |
| EXPECT_TRUE(VerifyVectorUint8(output[1].blob.data, output[1].blob.data_length, |
| appData)); |
| } |
| |
| TEST(ConvertToMessage, GetKeyCharacteristicsRequest) { |
| // Prepare. |
| auto input = ::arc::mojom::GetKeyCharacteristicsRequest::New( |
| std::vector<uint8_t>(kBlob1.begin(), kBlob1.end()), |
| std::vector<uint8_t>(kBlob2.begin(), kBlob2.end()), |
| std::vector<uint8_t>(kBlob3.begin(), kBlob3.end())); |
| |
| // Convert. |
| auto output = MakeGetKeyCharacteristicsRequest(input); |
| |
| // Verify. |
| EXPECT_TRUE(VerifyVectorUint8(output->key_blob.key_material, |
| output->key_blob.key_material_size, |
| input->key_blob)); |
| ASSERT_EQ(output->additional_params.size(), 2); |
| EXPECT_TRUE(VerifyVectorUint8(output->additional_params[0].blob.data, |
| output->additional_params[0].blob.data_length, |
| input->client_id)); |
| EXPECT_TRUE(VerifyVectorUint8(output->additional_params[1].blob.data, |
| output->additional_params[1].blob.data_length, |
| input->app_data)); |
| } |
| |
| TEST(ConvertToMessage, GenerateKeyRequest) { |
| // Prepare. |
| std::vector<arc::mojom::KeyParameterPtr> input = KeyParameterVector(); |
| |
| // Convert. |
| auto output = MakeGenerateKeyRequest(input); |
| |
| // Verify. |
| EXPECT_TRUE(VerifyKeyParameters(output->key_description, input)); |
| } |
| |
| TEST(ConvertToMessage, ImportKeyRequest) { |
| // Prepare. |
| auto input = arc::mojom::ImportKeyRequest::New( |
| KeyParameterVector(), arc::mojom::KeyFormat::PKCS8, |
| std::vector<uint8_t>(kBlob1.begin(), kBlob1.end())); |
| |
| // Convert. |
| auto output = MakeImportKeyRequest(std::move(input)); |
| |
| // Verify. |
| EXPECT_EQ(static_cast<keymaster_key_format_t>(input->key_format), |
| output->key_format); |
| EXPECT_TRUE( |
| VerifyKeyParameters(output->key_description, input->key_description)); |
| EXPECT_TRUE(VerifyVectorUint8(output->key_data, output->key_data_length, |
| input->key_data)); |
| } |
| |
| TEST(ConvertToMessage, ExportKeyRequest) { |
| // Prepare. |
| auto input = arc::mojom::ExportKeyRequest::New( |
| arc::mojom::KeyFormat::RAW, |
| std::vector<uint8_t>(kBlob1.begin(), kBlob1.end()), |
| std::vector<uint8_t>(kBlob2.begin(), kBlob2.end()), |
| std::vector<uint8_t>(kBlob3.begin(), kBlob3.end())); |
| |
| // Convert. |
| auto output = MakeExportKeyRequest(input); |
| |
| // Verify. |
| EXPECT_EQ(static_cast<keymaster_key_format_t>(input->key_format), |
| output->key_format); |
| ASSERT_EQ(2, output->additional_params.size()); |
| EXPECT_EQ(KM_TAG_APPLICATION_ID, output->additional_params[0].tag); |
| EXPECT_EQ(KM_TAG_APPLICATION_DATA, output->additional_params[1].tag); |
| EXPECT_TRUE(VerifyVectorUint8(output->additional_params[0].blob.data, |
| output->additional_params[0].blob.data_length, |
| input->client_id)); |
| EXPECT_TRUE(VerifyVectorUint8(output->additional_params[1].blob.data, |
| output->additional_params[1].blob.data_length, |
| input->app_data)); |
| EXPECT_TRUE(VerifyVectorUint8(output->key_blob.key_material, |
| output->key_blob.key_material_size, |
| input->key_blob)); |
| } |
| |
| TEST(ConvertToMojo, ExportKeyResult) { |
| // Prepare. |
| ::keymaster::ExportKeyResponse input; |
| input.error = KM_ERROR_OK; |
| input.SetKeyMaterial(kBlob1.data(), kBlob1.size()); |
| |
| // Convert. |
| auto output = MakeExportKeyResult(input); |
| |
| // Verify. |
| EXPECT_EQ(output->error, input.error); |
| EXPECT_TRUE(VerifyVectorUint8(input.key_data, input.key_data_length, |
| output->key_material)); |
| } |
| |
| TEST(ConvertToMojo, ExportKeyResultError) { |
| // Prepare. |
| ::keymaster::ExportKeyResponse input; |
| input.error = KM_ERROR_UNSUPPORTED_KEY_FORMAT; |
| input.SetKeyMaterial(reinterpret_cast<void*>(0xDEADBEEF), -1337); |
| |
| // Convert. |
| auto output = MakeExportKeyResult(input); |
| |
| // Verify. |
| EXPECT_EQ(output->error, input.error); |
| EXPECT_EQ(output->key_material.size(), 0); |
| } |
| |
| TEST(ConvertToMessage, AttestKeyRequest) { |
| // Prepare. |
| auto input = arc::mojom::AttestKeyRequest::New( |
| std::vector<uint8_t>(kBlob1.begin(), kBlob1.end()), KeyParameterVector()); |
| |
| // Convert. |
| auto output = MakeAttestKeyRequest(input); |
| |
| // Verify. |
| EXPECT_TRUE(VerifyVectorUint8(output->key_blob.key_material, |
| output->key_blob.key_material_size, |
| input->key_to_attest)); |
| EXPECT_TRUE(VerifyKeyParameters(output->attest_params, input->attest_params)); |
| } |
| |
| TEST(ConvertToMessage, UpgradeKeyRequest) { |
| // Prepare. |
| auto input = arc::mojom::UpgradeKeyRequest::New( |
| std::vector<uint8_t>(kBlob1.begin(), kBlob1.end()), KeyParameterVector()); |
| |
| // Convert. |
| auto output = MakeUpgradeKeyRequest(input); |
| |
| // Verify. |
| EXPECT_TRUE(VerifyVectorUint8(output->key_blob.key_material, |
| output->key_blob.key_material_size, |
| input->key_blob_to_upgrade)); |
| EXPECT_TRUE( |
| VerifyKeyParameters(output->upgrade_params, input->upgrade_params)); |
| } |
| |
| TEST(ConvertToMessage, BeginOperationRequest) { |
| // Prepare. |
| auto input = arc::mojom::BeginRequest::New( |
| arc::mojom::KeyPurpose::DERIVE_KEY, |
| std::vector<uint8_t>(kBlob1.begin(), kBlob1.end()), KeyParameterVector()); |
| |
| // Convert. |
| auto output = MakeBeginOperationRequest(input); |
| |
| // Verify. |
| EXPECT_EQ(output->purpose, static_cast<keymaster_purpose_t>(input->purpose)); |
| EXPECT_TRUE(VerifyVectorUint8(output->key_blob.key_material, |
| output->key_blob.key_material_size, |
| input->key)); |
| EXPECT_TRUE(VerifyKeyParameters(output->additional_params, input->in_params)); |
| } |
| |
| TEST(ConvertToMessage, UpdateOperationRequest) { |
| // Prepare. |
| auto input = arc::mojom::UpdateRequest::New( |
| 65537, KeyParameterVector(), |
| std::vector<uint8_t>(kBlob1.begin(), kBlob1.end())); |
| |
| // Convert. |
| auto output = MakeUpdateOperationRequest(input); |
| |
| // Verify. |
| EXPECT_EQ(output->op_handle, input->op_handle); |
| EXPECT_TRUE(VerifyVectorUint8(output->input.begin(), |
| output->input.available_read(), input->input)); |
| EXPECT_TRUE(VerifyKeyParameters(output->additional_params, input->in_params)); |
| } |
| |
| TEST(ConvertToMessage, FinishOperationRequest) { |
| // Prepare. |
| auto input = arc::mojom::FinishRequest::New( |
| 65537, KeyParameterVector(), |
| std::vector<uint8_t>(kBlob1.begin(), kBlob1.end()), |
| std::vector<uint8_t>(kBlob2.begin(), kBlob2.end())); |
| |
| // Convert. |
| auto output = MakeFinishOperationRequest(input); |
| |
| // Verify. |
| EXPECT_EQ(output->op_handle, input->op_handle); |
| EXPECT_TRUE(VerifyVectorUint8(output->signature.begin(), |
| output->signature.available_read(), |
| input->signature)); |
| EXPECT_TRUE(VerifyVectorUint8(output->input.begin(), |
| output->input.available_read(), input->input)); |
| EXPECT_TRUE(VerifyKeyParameters(output->additional_params, input->in_params)); |
| } |
| |
| } // namespace keymaster |
| } // namespace arc |