blob: dde1be4033e89b6d5b065c52b8cdec59abc9a21b [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 <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