blob: 88be9bbf3f97c6ddf30b4fd6e84380bf4bd14207 [file] [log] [blame]
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
#include "tink/keyset_handle_builder.h"
#include <cstdint>
#include <memory>
#include <set>
#include <string>
#include <utility>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/container/flat_hash_map.h"
#include "absl/memory/memory.h"
#include "absl/status/status.h"
#include "absl/strings/string_view.h"
#include "tink/aead.h"
#include "tink/aead/aes_gcm_parameters.h"
#include "tink/config/global_registry.h"
#include "tink/config/tink_config.h"
#include "tink/core/key_type_manager.h"
#include "tink/core/template_util.h"
#include "tink/input_stream.h"
#include "tink/insecure_secret_key_access.h"
#include "tink/internal/legacy_proto_key.h"
#include "tink/internal/legacy_proto_parameters.h"
#include "tink/internal/proto_key_serialization.h"
#include "tink/internal/proto_parameters_serialization.h"
#include "tink/key_status.h"
#include "tink/keyset_handle.h"
#include "tink/mac.h"
#include "tink/mac/aes_cmac_key.h"
#include "tink/mac/aes_cmac_parameters.h"
#include "tink/mac/mac_key_templates.h"
#include "tink/partial_key_access.h"
#include "tink/primitive_set.h"
#include "tink/primitive_wrapper.h"
#include "tink/registry.h"
#include "tink/restricted_data.h"
#include "tink/subtle/random.h"
#include "tink/util/status.h"
#include "tink/util/statusor.h"
#include "tink/util/test_matchers.h"
#include "tink/util/test_util.h"
#include "proto/aes_cmac.pb.h"
#include "proto/aes_gcm.pb.h"
#include "proto/tink.pb.h"
namespace crypto {
namespace tink {
namespace {
using ::crypto::tink::test::AddTinkKey;
using ::crypto::tink::test::IsOk;
using ::crypto::tink::test::IsOkAndHolds;
using ::crypto::tink::test::StatusIs;
using ::google::crypto::tink::AesCmacParams;
using ::google::crypto::tink::AesGcmKey;
using ::google::crypto::tink::AesGcmKeyFormat;
using ::google::crypto::tink::KeyData;
using ::google::crypto::tink::Keyset;
using ::google::crypto::tink::KeyStatusType;
using ::google::crypto::tink::KeyTemplate;
using ::google::crypto::tink::OutputPrefixType;
using ::testing::_;
using ::testing::Eq;
using ::testing::IsFalse;
using ::testing::IsTrue;
using ::testing::SizeIs;
using ::testing::Test;
class KeysetHandleBuilderTest : public Test {
protected:
void SetUp() override {
util::Status status = TinkConfig::Register();
ASSERT_TRUE(status.ok()) << status;
}
};
using KeysetHandleBuilderDeathTest = KeysetHandleBuilderTest;
util::StatusOr<internal::LegacyProtoParameters> CreateLegacyProtoParameters(
KeyTemplate key_template) {
util::StatusOr<internal::ProtoParametersSerialization> serialization =
internal::ProtoParametersSerialization::Create(key_template);
if (!serialization.ok()) return serialization.status();
return internal::LegacyProtoParameters(*serialization);
}
TEST_F(KeysetHandleBuilderTest, BuildWithSingleKey) {
util::StatusOr<internal::LegacyProtoParameters> parameters =
CreateLegacyProtoParameters(MacKeyTemplates::AesCmac());
ASSERT_THAT(parameters.status(), IsOk());
KeysetHandleBuilder::Entry entry =
KeysetHandleBuilder::Entry::CreateFromCopyableParams(
*parameters, KeyStatus::kEnabled, /*is_primary=*/true,
/*id=*/123);
util::StatusOr<KeysetHandle> handle =
KeysetHandleBuilder().AddEntry(std::move(entry)).Build();
ASSERT_THAT(handle.status(), IsOk());
EXPECT_THAT(*handle, SizeIs(1));
EXPECT_THAT((*handle)[0].GetStatus(), Eq(KeyStatus::kEnabled));
EXPECT_THAT((*handle)[0].GetId(), Eq(123));
EXPECT_THAT((*handle)[0].IsPrimary(), IsTrue());
EXPECT_THAT((*handle)[0].GetKey()->GetParameters().HasIdRequirement(),
IsTrue());
}
TEST_F(KeysetHandleBuilderTest, BuildWithMultipleKeys) {
util::StatusOr<internal::LegacyProtoParameters> parameters =
CreateLegacyProtoParameters(MacKeyTemplates::AesCmac());
ASSERT_THAT(parameters.status(), IsOk());
KeysetHandleBuilder::Entry entry0 =
KeysetHandleBuilder::Entry::CreateFromCopyableParams(
*parameters, KeyStatus::kDestroyed,
/*is_primary=*/false,
/*id=*/123);
KeysetHandleBuilder::Entry entry1 =
KeysetHandleBuilder::Entry::CreateFromCopyableParams(
*parameters, KeyStatus::kEnabled, /*is_primary=*/true,
/*id=*/456);
KeysetHandleBuilder::Entry entry2 =
KeysetHandleBuilder::Entry::CreateFromCopyableParams(
*parameters, KeyStatus::kDisabled,
/*is_primary=*/false, /*id=*/789);
util::StatusOr<KeysetHandle> handle = KeysetHandleBuilder()
.AddEntry(std::move(entry0))
.AddEntry(std::move(entry1))
.AddEntry(std::move(entry2))
.Build();
ASSERT_THAT(handle.status(), IsOk());
EXPECT_THAT(*handle, SizeIs(3));
EXPECT_THAT((*handle)[0].GetStatus(), Eq(KeyStatus::kDestroyed));
EXPECT_THAT((*handle)[0].GetId(), Eq(123));
EXPECT_THAT((*handle)[0].IsPrimary(), IsFalse());
EXPECT_THAT((*handle)[0].GetKey()->GetParameters().HasIdRequirement(),
IsTrue());
EXPECT_THAT((*handle)[1].GetStatus(), Eq(KeyStatus::kEnabled));
EXPECT_THAT((*handle)[1].GetId(), Eq(456));
EXPECT_THAT((*handle)[1].IsPrimary(), IsTrue());
EXPECT_THAT((*handle)[1].GetKey()->GetParameters().HasIdRequirement(),
IsTrue());
EXPECT_THAT((*handle)[2].GetStatus(), Eq(KeyStatus::kDisabled));
EXPECT_THAT((*handle)[2].GetId(), Eq(789));
EXPECT_THAT((*handle)[2].IsPrimary(), IsFalse());
EXPECT_THAT((*handle)[2].GetKey()->GetParameters().HasIdRequirement(),
IsTrue());
}
TEST_F(KeysetHandleBuilderTest, BuildCopy) {
util::StatusOr<internal::LegacyProtoParameters> parameters =
CreateLegacyProtoParameters(MacKeyTemplates::AesCmac());
ASSERT_THAT(parameters.status(), IsOk());
KeysetHandleBuilder::Entry entry0 =
KeysetHandleBuilder::Entry::CreateFromCopyableParams(
*parameters, KeyStatus::kDestroyed,
/*is_primary=*/false,
/*id=*/123);
KeysetHandleBuilder::Entry entry1 =
KeysetHandleBuilder::Entry::CreateFromCopyableParams(
*parameters, KeyStatus::kEnabled, /*is_primary=*/true,
/*id=*/456);
KeysetHandleBuilder::Entry entry2 =
KeysetHandleBuilder::Entry::CreateFromCopyableParams(
*parameters, KeyStatus::kDisabled,
/*is_primary=*/false, /*id=*/789);
util::StatusOr<KeysetHandle> handle = KeysetHandleBuilder()
.AddEntry(std::move(entry0))
.AddEntry(std::move(entry1))
.AddEntry(std::move(entry2))
.Build();
ASSERT_THAT(handle.status(), IsOk());
util::StatusOr<KeysetHandle> copy = KeysetHandleBuilder(*handle).Build();
ASSERT_THAT(copy.status(), IsOk());
EXPECT_THAT(copy->size(), Eq(3));
EXPECT_THAT((*copy)[0].GetStatus(), Eq(KeyStatus::kDestroyed));
EXPECT_THAT((*copy)[0].GetId(), Eq(123));
EXPECT_THAT((*copy)[0].IsPrimary(), IsFalse());
EXPECT_THAT((*copy)[0].GetKey()->GetParameters().HasIdRequirement(),
IsTrue());
EXPECT_THAT((*copy)[1].GetStatus(), Eq(KeyStatus::kEnabled));
EXPECT_THAT((*copy)[1].GetId(), Eq(456));
EXPECT_THAT((*copy)[1].IsPrimary(), IsTrue());
EXPECT_THAT((*copy)[1].GetKey()->GetParameters().HasIdRequirement(),
IsTrue());
EXPECT_THAT((*copy)[2].GetStatus(), Eq(KeyStatus::kDisabled));
EXPECT_THAT((*copy)[2].GetId(), Eq(789));
EXPECT_THAT((*copy)[2].IsPrimary(), IsFalse());
EXPECT_THAT((*copy)[2].GetKey()->GetParameters().HasIdRequirement(),
IsTrue());
}
TEST_F(KeysetHandleBuilderTest, IsPrimary) {
util::StatusOr<internal::LegacyProtoParameters> parameters =
CreateLegacyProtoParameters(MacKeyTemplates::AesCmac());
ASSERT_THAT(parameters.status(), IsOk());
KeysetHandleBuilder::Entry entry =
KeysetHandleBuilder::Entry::CreateFromCopyableParams(*parameters,
KeyStatus::kEnabled,
/*is_primary=*/false,
/*id=*/123);
EXPECT_THAT(entry.IsPrimary(), IsFalse());
entry.SetPrimary();
EXPECT_THAT(entry.IsPrimary(), IsTrue());
}
TEST_F(KeysetHandleBuilderTest, SetAndGetStatus) {
util::StatusOr<internal::LegacyProtoParameters> parameters =
CreateLegacyProtoParameters(MacKeyTemplates::AesCmac());
ASSERT_THAT(parameters.status(), IsOk());
KeysetHandleBuilder::Entry entry =
KeysetHandleBuilder::Entry::CreateFromCopyableParams(
*parameters, KeyStatus::kEnabled, /*is_primary=*/false,
/*id=*/123);
entry.SetStatus(KeyStatus::kDisabled);
EXPECT_THAT(entry.GetStatus(), Eq(KeyStatus::kDisabled));
entry.SetStatus(KeyStatus::kEnabled);
EXPECT_THAT(entry.GetStatus(), Eq(KeyStatus::kEnabled));
entry.SetStatus(KeyStatus::kDestroyed);
EXPECT_THAT(entry.GetStatus(), Eq(KeyStatus::kDestroyed));
}
TEST_F(KeysetHandleBuilderTest, BuildWithRandomId) {
util::StatusOr<internal::LegacyProtoParameters> parameters =
CreateLegacyProtoParameters(MacKeyTemplates::AesCmac());
ASSERT_THAT(parameters.status(), IsOk());
KeysetHandleBuilder::Entry primary =
KeysetHandleBuilder::Entry::CreateFromCopyableParams(
*parameters, KeyStatus::kEnabled, /*is_primary=*/true);
KeysetHandleBuilder builder;
builder.AddEntry(std::move(primary));
int num_non_primary_entries = 1 << 16;
for (int i = 0; i < num_non_primary_entries; ++i) {
KeysetHandleBuilder::Entry non_primary =
KeysetHandleBuilder::Entry::CreateFromCopyableParams(
*parameters, KeyStatus::kEnabled, /*is_primary=*/false);
builder.AddEntry(std::move(non_primary));
}
util::StatusOr<KeysetHandle> handle = builder.Build();
ASSERT_THAT(handle.status(), IsOk());
std::set<int> ids;
for (int i = 0; i < handle->size(); ++i) {
ids.insert((*handle)[i].GetId());
}
EXPECT_THAT(ids, SizeIs(num_non_primary_entries + 1));
}
TEST_F(KeysetHandleBuilderTest, BuildWithRandomIdAfterFixedId) {
util::StatusOr<internal::LegacyProtoParameters> parameters =
CreateLegacyProtoParameters(MacKeyTemplates::AesCmac());
ASSERT_THAT(parameters.status(), IsOk());
KeysetHandleBuilder::Entry fixed =
KeysetHandleBuilder::Entry::CreateFromCopyableParams(
*parameters, KeyStatus::kEnabled, /*is_primary=*/true, /*id=*/123);
KeysetHandleBuilder::Entry random =
KeysetHandleBuilder::Entry::CreateFromCopyableParams(
*parameters, KeyStatus::kEnabled, /*is_primary=*/false);
util::StatusOr<KeysetHandle> handle = KeysetHandleBuilder()
.AddEntry(std::move(fixed))
.AddEntry(std::move(random))
.Build();
ASSERT_THAT(handle.status(), IsOk());
EXPECT_THAT(*handle, SizeIs(2));
EXPECT_THAT((*handle)[0].GetId(), Eq(123));
}
TEST_F(KeysetHandleBuilderTest, BuildWithFixedIdAfterRandomIdFails) {
util::StatusOr<internal::LegacyProtoParameters> parameters =
CreateLegacyProtoParameters(MacKeyTemplates::AesCmac());
ASSERT_THAT(parameters.status(), IsOk());
KeysetHandleBuilder::Entry random =
KeysetHandleBuilder::Entry::CreateFromCopyableParams(
*parameters, KeyStatus::kEnabled, /*is_primary=*/false);
KeysetHandleBuilder::Entry fixed =
KeysetHandleBuilder::Entry::CreateFromCopyableParams(
*parameters, KeyStatus::kEnabled, /*is_primary=*/true, /*id=*/123);
util::StatusOr<KeysetHandle> handle = KeysetHandleBuilder()
.AddEntry(std::move(random))
.AddEntry(std::move(fixed))
.Build();
ASSERT_THAT(handle.status(), StatusIs(absl::StatusCode::kFailedPrecondition));
}
TEST_F(KeysetHandleBuilderDeathTest, AddEntryToAnotherBuilderCrashes) {
util::StatusOr<internal::LegacyProtoParameters> parameters =
CreateLegacyProtoParameters(MacKeyTemplates::AesCmac());
ASSERT_THAT(parameters.status(), IsOk());
KeysetHandleBuilder::Entry entry =
KeysetHandleBuilder::Entry::CreateFromCopyableParams(
*parameters, KeyStatus::kEnabled, /*is_primary=*/true, /*id=*/123);
KeysetHandleBuilder builder0;
builder0.AddEntry(std::move(entry));
KeysetHandleBuilder builder1;
EXPECT_DEATH_IF_SUPPORTED(
builder1.AddEntry(std::move(builder0[0])),
"Keyset handle builder entry already added to a builder.");
}
TEST_F(KeysetHandleBuilderDeathTest, ReAddEntryToSameBuilderCrashes) {
util::StatusOr<internal::LegacyProtoParameters> parameters =
CreateLegacyProtoParameters(MacKeyTemplates::AesCmac());
ASSERT_THAT(parameters.status(), IsOk());
KeysetHandleBuilder::Entry entry =
KeysetHandleBuilder::Entry::CreateFromCopyableParams(
*parameters, KeyStatus::kEnabled, /*is_primary=*/true, /*id=*/123);
KeysetHandleBuilder builder;
builder.AddEntry(std::move(entry));
EXPECT_DEATH_IF_SUPPORTED(
builder.AddEntry(std::move(builder[0])),
"Keyset handle builder entry already added to a builder.");
}
TEST_F(KeysetHandleBuilderDeathTest,
AddDereferencedEntryToAnotherBuilderCrashes) {
util::StatusOr<internal::LegacyProtoParameters> parameters =
CreateLegacyProtoParameters(MacKeyTemplates::AesCmac());
ASSERT_THAT(parameters.status(), IsOk());
KeysetHandleBuilder::Entry entry =
KeysetHandleBuilder::Entry::CreateFromCopyableParams(
*parameters, KeyStatus::kEnabled, /*is_primary=*/true, /*id=*/123);
KeysetHandleBuilder builder0;
builder0.AddEntry(std::move(entry));
KeysetHandleBuilder builder1;
EXPECT_DEATH_IF_SUPPORTED(
builder1.AddEntry(std::move(*&(builder0[0]))),
"Keyset handle builder entry already added to a builder.");
}
TEST_F(KeysetHandleBuilderTest, RemoveEntry) {
util::StatusOr<internal::LegacyProtoParameters> parameters =
CreateLegacyProtoParameters(MacKeyTemplates::AesCmac());
ASSERT_THAT(parameters.status(), IsOk());
KeysetHandleBuilder::Entry entry0 =
KeysetHandleBuilder::Entry::CreateFromCopyableParams(
*parameters, KeyStatus::kEnabled, /*is_primary=*/false, /*id=*/123);
KeysetHandleBuilder::Entry entry1 =
KeysetHandleBuilder::Entry::CreateFromCopyableParams(
*parameters, KeyStatus::kEnabled, /*is_primary=*/true, /*id=*/456);
util::StatusOr<KeysetHandle> handle0 = KeysetHandleBuilder()
.AddEntry(std::move(entry0))
.AddEntry(std::move(entry1))
.Build();
ASSERT_THAT(handle0.status(), IsOk());
ASSERT_THAT(*handle0, SizeIs(2));
util::StatusOr<KeysetHandle> handle1 =
KeysetHandleBuilder(*handle0).RemoveEntry(0).Build();
ASSERT_THAT(handle1.status(), IsOk());
ASSERT_THAT(*handle1, SizeIs(1));
EXPECT_THAT((*handle1)[0].GetStatus(), Eq(KeyStatus::kEnabled));
EXPECT_THAT((*handle1)[0].GetId(), Eq(456));
EXPECT_THAT((*handle1)[0].IsPrimary(), IsTrue());
EXPECT_THAT((*handle1)[0].GetKey()->GetParameters().HasIdRequirement(),
IsTrue());
}
TEST_F(KeysetHandleBuilderDeathTest, RemoveOutofRangeIndexEntryCrashes) {
util::StatusOr<internal::LegacyProtoParameters> parameters =
CreateLegacyProtoParameters(MacKeyTemplates::AesCmac());
ASSERT_THAT(parameters.status(), IsOk());
KeysetHandleBuilder::Entry entry =
KeysetHandleBuilder::Entry::CreateFromCopyableParams(
*parameters, KeyStatus::kEnabled, /*is_primary=*/true, /*id=*/123);
util::StatusOr<KeysetHandle> handle =
KeysetHandleBuilder().AddEntry(std::move(entry)).Build();
ASSERT_THAT(handle.status(), IsOk());
ASSERT_THAT(*handle, SizeIs(1));
EXPECT_DEATH_IF_SUPPORTED(
KeysetHandleBuilder(*handle).RemoveEntry(1),
"Keyset handle builder entry removal index out of range.");
}
TEST_F(KeysetHandleBuilderTest, Size) {
util::StatusOr<internal::LegacyProtoParameters> parameters =
CreateLegacyProtoParameters(MacKeyTemplates::AesCmac());
ASSERT_THAT(parameters.status(), IsOk());
KeysetHandleBuilder::Entry entry0 =
KeysetHandleBuilder::Entry::CreateFromCopyableParams(
*parameters, KeyStatus::kDestroyed,
/*is_primary=*/false,
/*id=*/123);
KeysetHandleBuilder::Entry entry1 =
KeysetHandleBuilder::Entry::CreateFromCopyableParams(
*parameters, KeyStatus::kEnabled, /*is_primary=*/true,
/*id=*/456);
KeysetHandleBuilder builder;
ASSERT_THAT(builder, SizeIs(0));
builder.AddEntry(std::move(entry0));
ASSERT_THAT(builder, SizeIs(1));
builder.AddEntry(std::move(entry1));
EXPECT_THAT(builder, SizeIs(2));
}
TEST_F(KeysetHandleBuilderTest, NoPrimaryFails) {
util::StatusOr<internal::LegacyProtoParameters> parameters =
CreateLegacyProtoParameters(MacKeyTemplates::AesCmac());
ASSERT_THAT(parameters.status(), IsOk());
KeysetHandleBuilder::Entry entry0 =
KeysetHandleBuilder::Entry::CreateFromCopyableParams(
*parameters, KeyStatus::kEnabled, /*is_primary=*/false,
/*id=*/123);
KeysetHandleBuilder::Entry entry1 =
KeysetHandleBuilder::Entry::CreateFromCopyableParams(
*parameters, KeyStatus::kEnabled, /*is_primary=*/false,
/*id=*/456);
util::StatusOr<KeysetHandle> handle = KeysetHandleBuilder()
.AddEntry(std::move(entry0))
.AddEntry(std::move(entry1))
.Build();
ASSERT_THAT(handle.status(), StatusIs(absl::StatusCode::kFailedPrecondition));
}
TEST_F(KeysetHandleBuilderTest, RemovePrimaryFails) {
util::StatusOr<internal::LegacyProtoParameters> parameters =
CreateLegacyProtoParameters(MacKeyTemplates::AesCmac());
ASSERT_THAT(parameters.status(), IsOk());
KeysetHandleBuilder::Entry entry0 =
KeysetHandleBuilder::Entry::CreateFromCopyableParams(
*parameters, KeyStatus::kEnabled, /*is_primary=*/true,
/*id=*/123);
KeysetHandleBuilder::Entry entry1 =
KeysetHandleBuilder::Entry::CreateFromCopyableParams(
*parameters, KeyStatus::kEnabled, /*is_primary=*/false,
/*id=*/456);
util::StatusOr<KeysetHandle> handle = KeysetHandleBuilder()
.AddEntry(std::move(entry0))
.AddEntry(std::move(entry1))
.RemoveEntry(0)
.Build();
ASSERT_THAT(handle.status(), StatusIs(absl::StatusCode::kFailedPrecondition));
}
TEST_F(KeysetHandleBuilderTest, AddPrimaryClearsOtherPrimary) {
util::StatusOr<internal::LegacyProtoParameters> parameters =
CreateLegacyProtoParameters(MacKeyTemplates::AesCmac());
ASSERT_THAT(parameters.status(), IsOk());
KeysetHandleBuilder builder;
builder.AddEntry(KeysetHandleBuilder::Entry::CreateFromCopyableParams(
*parameters, KeyStatus::kEnabled,
/*is_primary=*/true,
/*id=*/123));
builder.AddEntry(KeysetHandleBuilder::Entry::CreateFromCopyableParams(
*parameters, KeyStatus::kEnabled,
/*is_primary=*/true,
/*id=*/456));
ASSERT_THAT(builder[0].IsPrimary(), IsFalse());
ASSERT_THAT(builder[1].IsPrimary(), IsTrue());
}
TEST_F(KeysetHandleBuilderTest, NoIdStrategySucceeds) {
util::StatusOr<internal::LegacyProtoParameters> parameters =
CreateLegacyProtoParameters(MacKeyTemplates::AesCmac());
ASSERT_THAT(parameters.status(), IsOk());
KeysetHandleBuilder::Entry entry =
KeysetHandleBuilder::Entry::CreateFromCopyableParams(
*parameters, KeyStatus::kEnabled, /*is_primary=*/true);
util::StatusOr<KeysetHandle> handle =
KeysetHandleBuilder().AddEntry(std::move(entry)).Build();
ASSERT_THAT(handle, IsOk());
}
TEST_F(KeysetHandleBuilderTest, DuplicateId) {
util::StatusOr<internal::LegacyProtoParameters> parameters =
CreateLegacyProtoParameters(MacKeyTemplates::AesCmac());
ASSERT_THAT(parameters.status(), IsOk());
util::StatusOr<KeysetHandle> handle =
KeysetHandleBuilder()
.AddEntry(KeysetHandleBuilder::Entry::CreateFromCopyableParams(
*parameters, KeyStatus::kEnabled,
/*is_primary=*/true,
/*id=*/123))
.AddEntry(KeysetHandleBuilder::Entry::CreateFromCopyableParams(
*parameters, KeyStatus::kEnabled,
/*is_primary=*/false,
/*id=*/123))
.Build();
ASSERT_THAT(handle.status(), StatusIs(absl::StatusCode::kAlreadyExists));
}
TEST_F(KeysetHandleBuilderTest, CreateBuilderEntryFromParams) {
util::StatusOr<AesCmacParameters> params = AesCmacParameters::Create(
/*key_size_in_bytes=*/32, /*cryptographic_tag_size_in_bytes=*/16,
AesCmacParameters::Variant::kTink);
ASSERT_THAT(params, IsOk());
KeysetHandleBuilder::Entry entry =
KeysetHandleBuilder::Entry::CreateFromParams(
absl::make_unique<AesCmacParameters>(std::move(*params)),
KeyStatus::kEnabled, /*is_primary=*/true);
util::StatusOr<KeysetHandle> handle =
KeysetHandleBuilder().AddEntry(std::move(entry)).Build();
ASSERT_THAT(handle.status(), IsOk());
}
TEST_F(KeysetHandleBuilderTest, CreateBuilderEntryFromLegacyKey) {
Keyset keyset;
Keyset::Key key;
AddTinkKey("first_key_type", 11, key, KeyStatusType::DISABLED,
KeyData::SYMMETRIC, &keyset);
util::StatusOr<internal::ProtoKeySerialization> serialization =
internal::ProtoKeySerialization::Create(
key.key_data().type_url(),
RestrictedData(key.SerializeAsString(),
InsecureSecretKeyAccess::Get()),
key.key_data().key_material_type(), key.output_prefix_type(),
key.key_id());
util::StatusOr<internal::LegacyProtoKey> proto_key =
internal::LegacyProtoKey::Create(*serialization,
InsecureSecretKeyAccess::Get());
ASSERT_THAT(proto_key.status(), IsOk());
KeysetHandleBuilder::Entry entry = KeysetHandleBuilder::Entry::CreateFromKey(
absl::make_unique<internal::LegacyProtoKey>(std::move(*proto_key)),
KeyStatus::kEnabled, /*is_primary=*/true);
util::StatusOr<KeysetHandle> handle =
KeysetHandleBuilder().AddEntry(std::move(entry)).Build();
ASSERT_THAT(handle.status(), IsOk());
}
TEST_F(KeysetHandleBuilderTest, CreateBuilderEntryFromKey) {
util::StatusOr<AesCmacParameters> params = AesCmacParameters::Create(
/*key_size_in_bytes=*/32, /*cryptographic_tag_size_in_bytes=*/16,
AesCmacParameters::Variant::kTink);
ASSERT_THAT(params, IsOk());
RestrictedData secret = RestrictedData(32);
util::StatusOr<AesCmacKey> key = AesCmacKey::Create(
*params, secret, /*id_requirement=*/123, GetPartialKeyAccess());
ASSERT_THAT(key.status(), IsOk());
KeysetHandleBuilder::Entry entry = KeysetHandleBuilder::Entry::CreateFromKey(
absl::make_unique<AesCmacKey>(std::move(*key)), KeyStatus::kEnabled,
/*is_primary=*/true);
util::StatusOr<KeysetHandle> handle =
KeysetHandleBuilder().AddEntry(std::move(entry)).Build();
ASSERT_THAT(handle.status(), IsOk());
}
TEST_F(KeysetHandleBuilderTest,
MergeTwoKeysetsWithTheSameIdButNoIdRequirementWorks) {
util::StatusOr<AesCmacParameters> params = AesCmacParameters::Create(
/*key_size_in_bytes=*/32, /*cryptographic_tag_size_in_bytes=*/16,
AesCmacParameters::Variant::kNoPrefix);
ASSERT_THAT(params, IsOk());
KeysetHandleBuilder::Entry entry1 =
KeysetHandleBuilder::Entry::CreateFromParams(
absl::make_unique<AesCmacParameters>(std::move(*params)),
KeyStatus::kEnabled, /*is_primary=*/true);
entry1.SetFixedId(123);
util::StatusOr<KeysetHandle> handle1 =
KeysetHandleBuilder().AddEntry(std::move(entry1)).Build();
ASSERT_THAT(handle1.status(), IsOk());
KeysetHandleBuilder::Entry entry2 =
KeysetHandleBuilder::Entry::CreateFromParams(
absl::make_unique<AesCmacParameters>(std::move(*params)),
KeyStatus::kEnabled, /*is_primary=*/true);
entry2.SetFixedId(123);
util::StatusOr<KeysetHandle> handle2 =
KeysetHandleBuilder().AddEntry(std::move(entry2)).Build();
ASSERT_THAT(handle2.status(), IsOk());
// handle1 and handle2 each contain one key with the same ID, but no ID
// requirement. We can add them to a new keyset because they will get new,
// random and distinct IDs.
util::StatusOr<KeysetHandle> handle12 =
KeysetHandleBuilder()
.AddEntry(KeysetHandleBuilder::Entry::CreateFromKey(
(*handle1)[0].GetKey(), KeyStatus::kEnabled, /*is_primary=*/true))
.AddEntry(KeysetHandleBuilder::Entry::CreateFromKey(
(*handle2)[0].GetKey(), KeyStatus::kEnabled,
/*is_primary=*/false))
.Build();
ASSERT_THAT(handle12.status(), IsOk());
}
TEST_F(KeysetHandleBuilderTest, CreateBuilderEntryFromCopyableKey) {
Keyset keyset;
Keyset::Key key;
AddTinkKey("first_key_type", 11, key, KeyStatusType::DISABLED,
KeyData::SYMMETRIC, &keyset);
util::StatusOr<internal::ProtoKeySerialization> serialization =
internal::ProtoKeySerialization::Create(
key.key_data().type_url(),
RestrictedData(key.SerializeAsString(),
InsecureSecretKeyAccess::Get()),
key.key_data().key_material_type(), key.output_prefix_type(),
key.key_id());
util::StatusOr<internal::LegacyProtoKey> proto_key =
internal::LegacyProtoKey::Create(*serialization,
InsecureSecretKeyAccess::Get());
ASSERT_THAT(proto_key.status(), IsOk());
KeysetHandleBuilder::Entry entry =
KeysetHandleBuilder::Entry::CreateFromCopyableKey(
*proto_key, KeyStatus::kEnabled, /*is_primary=*/true);
util::StatusOr<KeysetHandle> handle =
KeysetHandleBuilder().AddEntry(std::move(entry)).Build();
ASSERT_THAT(handle.status(), IsOk());
}
TEST_F(KeysetHandleBuilderTest, CreateBuilderEntryFromParameters) {
util::StatusOr<internal::LegacyProtoParameters> parameters =
CreateLegacyProtoParameters(MacKeyTemplates::AesCmac());
ASSERT_THAT(parameters.status(), IsOk());
KeysetHandleBuilder::Entry entry =
KeysetHandleBuilder::Entry::CreateFromParams(
absl::make_unique<internal::LegacyProtoParameters>(*parameters),
KeyStatus::kEnabled, /*is_primary=*/true);
util::StatusOr<KeysetHandle> handle =
KeysetHandleBuilder().AddEntry(std::move(entry)).Build();
ASSERT_THAT(handle.status(), IsOk());
}
TEST_F(KeysetHandleBuilderTest, CreateBuilderEntryFromCopyableParameters) {
util::StatusOr<internal::LegacyProtoParameters> parameters =
CreateLegacyProtoParameters(MacKeyTemplates::AesCmac());
ASSERT_THAT(parameters.status(), IsOk());
KeysetHandleBuilder::Entry entry =
KeysetHandleBuilder::Entry::CreateFromCopyableParams(
*parameters, KeyStatus::kEnabled, /*is_primary=*/true);
util::StatusOr<KeysetHandle> handle =
KeysetHandleBuilder().AddEntry(std::move(entry)).Build();
ASSERT_THAT(handle.status(), IsOk());
}
TEST_F(KeysetHandleBuilderTest, UsePrimitiveFromLegacyProtoParams) {
util::StatusOr<internal::LegacyProtoParameters> parameters =
CreateLegacyProtoParameters(MacKeyTemplates::AesCmac());
ASSERT_THAT(parameters.status(), IsOk());
KeysetHandleBuilder::Entry entry =
KeysetHandleBuilder::Entry::CreateFromCopyableParams(
*parameters, KeyStatus::kEnabled, /*is_primary=*/true);
util::StatusOr<KeysetHandle> handle =
KeysetHandleBuilder().AddEntry(std::move(entry)).Build();
ASSERT_THAT(handle.status(), IsOk());
util::StatusOr<std::unique_ptr<Mac>> mac =
handle->GetPrimitive<crypto::tink::Mac>(ConfigGlobalRegistry());
ASSERT_THAT(mac.status(), IsOk());
util::StatusOr<std::string> tag = (*mac)->ComputeMac("some input");
ASSERT_THAT(tag.status(), IsOk());
util::Status verified = (*mac)->VerifyMac(*tag, "some input");
EXPECT_THAT(verified, IsOk());
}
TEST_F(KeysetHandleBuilderTest, UsePrimitiveFromParams) {
util::StatusOr<AesCmacParameters> params = AesCmacParameters::Create(
/*key_size_in_bytes=*/32, /*cryptographic_tag_size_in_bytes=*/16,
AesCmacParameters::Variant::kTink);
ASSERT_THAT(params, IsOk());
KeysetHandleBuilder::Entry entry =
KeysetHandleBuilder::Entry::CreateFromParams(
absl::make_unique<AesCmacParameters>(std::move(*params)),
KeyStatus::kEnabled, /*is_primary=*/true);
util::StatusOr<KeysetHandle> handle =
KeysetHandleBuilder().AddEntry(std::move(entry)).Build();
ASSERT_THAT(handle.status(), IsOk());
util::StatusOr<std::unique_ptr<Mac>> mac =
handle->GetPrimitive<crypto::tink::Mac>(ConfigGlobalRegistry());
ASSERT_THAT(mac.status(), IsOk());
util::StatusOr<std::string> tag = (*mac)->ComputeMac("some input");
ASSERT_THAT(tag.status(), IsOk());
util::Status verified = (*mac)->VerifyMac(*tag, "some input");
EXPECT_THAT(verified, IsOk());
}
TEST_F(KeysetHandleBuilderTest, UsePrimitiveFromLegacyProtoKey) {
AesCmacParams params;
params.set_tag_size(16);
google::crypto::tink::AesCmacKey key;
*key.mutable_params() = params;
key.set_version(0);
key.set_key_value(subtle::Random::GetRandomBytes(32));
util::StatusOr<internal::ProtoKeySerialization> serialization =
internal::ProtoKeySerialization::Create(
"type.googleapis.com/google.crypto.tink.AesCmacKey",
RestrictedData(key.SerializeAsString(),
InsecureSecretKeyAccess::Get()),
KeyData::SYMMETRIC, OutputPrefixType::TINK,
/*id_requirement=*/123);
ASSERT_THAT(serialization, IsOk());
util::StatusOr<internal::LegacyProtoKey> proto_key =
internal::LegacyProtoKey::Create(*serialization,
InsecureSecretKeyAccess::Get());
ASSERT_THAT(proto_key.status(), IsOk());
KeysetHandleBuilder::Entry entry =
KeysetHandleBuilder::Entry::CreateFromCopyableKey(
*proto_key, KeyStatus::kEnabled, /*is_primary=*/true);
util::StatusOr<KeysetHandle> handle =
KeysetHandleBuilder().AddEntry(std::move(entry)).Build();
ASSERT_THAT(handle.status(), IsOk());
util::StatusOr<std::unique_ptr<Mac>> mac =
handle->GetPrimitive<crypto::tink::Mac>(ConfigGlobalRegistry());
ASSERT_THAT(mac.status(), IsOk());
util::StatusOr<std::string> tag = (*mac)->ComputeMac("some input");
ASSERT_THAT(tag.status(), IsOk());
util::Status verified = (*mac)->VerifyMac(*tag, "some input");
EXPECT_THAT(verified, IsOk());
}
TEST_F(KeysetHandleBuilderTest, UsePrimitiveFromKey) {
util::StatusOr<AesCmacParameters> params = AesCmacParameters::Create(
/*key_size_in_bytes=*/32, /*cryptographic_tag_size_in_bytes=*/16,
AesCmacParameters::Variant::kTink);
ASSERT_THAT(params, IsOk());
RestrictedData secret = RestrictedData(32);
util::StatusOr<AesCmacKey> key = AesCmacKey::Create(
*params, secret, /*id_requirement=*/123, GetPartialKeyAccess());
ASSERT_THAT(key.status(), IsOk());
KeysetHandleBuilder::Entry entry = KeysetHandleBuilder::Entry::CreateFromKey(
absl::make_unique<AesCmacKey>(std::move(*key)), KeyStatus::kEnabled,
/*is_primary=*/true);
util::StatusOr<KeysetHandle> handle =
KeysetHandleBuilder().AddEntry(std::move(entry)).Build();
ASSERT_THAT(handle.status(), IsOk());
util::StatusOr<std::unique_ptr<Mac>> mac =
handle->GetPrimitive<crypto::tink::Mac>(ConfigGlobalRegistry());
ASSERT_THAT(mac.status(), IsOk());
util::StatusOr<std::string> tag = (*mac)->ComputeMac("some input");
ASSERT_THAT(tag.status(), IsOk());
util::Status verified = (*mac)->VerifyMac(*tag, "some input");
EXPECT_THAT(verified, IsOk());
}
TEST_F(KeysetHandleBuilderTest, BuildTwiceFails) {
util::StatusOr<internal::LegacyProtoParameters> parameters =
CreateLegacyProtoParameters(MacKeyTemplates::AesCmac());
ASSERT_THAT(parameters.status(), IsOk());
KeysetHandleBuilder::Entry entry =
KeysetHandleBuilder::Entry::CreateFromCopyableParams(
*parameters, KeyStatus::kEnabled, /*is_primary=*/true,
/*id=*/123);
KeysetHandleBuilder builder;
builder.AddEntry(std::move(entry));
EXPECT_THAT(builder.Build(), IsOk());
EXPECT_THAT(builder.Build().status(),
StatusIs(absl::StatusCode::kFailedPrecondition));
}
TEST_F(KeysetHandleBuilderTest, UsePrimitivesFromSplitKeyset) {
util::StatusOr<AesCmacParameters> params = AesCmacParameters::Create(
/*key_size_in_bytes=*/32, /*cryptographic_tag_size_in_bytes=*/16,
AesCmacParameters::Variant::kTink);
ASSERT_THAT(params, IsOk());
util::StatusOr<KeysetHandle> handle =
KeysetHandleBuilder()
.AddEntry(KeysetHandleBuilder::Entry::CreateFromCopyableParams(
*params, KeyStatus::kEnabled, /*is_primary=*/false))
.AddEntry(KeysetHandleBuilder::Entry::CreateFromCopyableParams(
*params, KeyStatus::kEnabled, /*is_primary=*/true))
.Build();
ASSERT_THAT(handle, IsOkAndHolds(SizeIs(2)));
util::StatusOr<KeysetHandle> handle0 =
KeysetHandleBuilder()
.AddEntry(KeysetHandleBuilder::Entry::CreateFromKey(
(*handle)[0].GetKey(), KeyStatus::kEnabled,
/*is_primary=*/true))
.Build();
ASSERT_THAT(handle0, IsOkAndHolds(SizeIs(1)));
ASSERT_THAT((*handle)[0].GetId(), Eq((*handle0)[0].GetId()));
util::StatusOr<KeysetHandle> handle1 =
KeysetHandleBuilder()
.AddEntry(KeysetHandleBuilder::Entry::CreateFromKey(
(*handle)[1].GetKey(), KeyStatus::kEnabled,
/*is_primary=*/true))
.Build();
ASSERT_THAT(handle1, IsOkAndHolds(SizeIs(1)));
ASSERT_THAT((*handle)[1].GetId(), Eq((*handle1)[0].GetId()));
util::StatusOr<std::unique_ptr<Mac>> mac0 =
handle0->GetPrimitive<crypto::tink::Mac>(ConfigGlobalRegistry());
ASSERT_THAT(mac0.status(), IsOk());
util::StatusOr<std::string> tag0 = (*mac0)->ComputeMac("some input");
ASSERT_THAT(tag0.status(), IsOk());
util::StatusOr<std::unique_ptr<Mac>> mac1 =
handle1->GetPrimitive<crypto::tink::Mac>(ConfigGlobalRegistry());
ASSERT_THAT(mac1.status(), IsOk());
util::StatusOr<std::string> tag1 = (*mac1)->ComputeMac("some other input");
ASSERT_THAT(tag1.status(), IsOk());
// Use original keyset to verify tags computed from new keysets.
util::StatusOr<std::unique_ptr<Mac>> mac =
handle->GetPrimitive<crypto::tink::Mac>(ConfigGlobalRegistry());
ASSERT_THAT(mac.status(), IsOk());
EXPECT_THAT((*mac)->VerifyMac(*tag0, "some input"), IsOk());
EXPECT_THAT((*mac)->VerifyMac(*tag1, "some other input"), IsOk());
}
class MockAeadPrimitiveWrapper : public PrimitiveWrapper<Aead, Aead> {
public:
MOCK_METHOD(util::StatusOr<std::unique_ptr<Aead>>, Wrap,
(std::unique_ptr<PrimitiveSet<Aead>> primitive_set),
(const override));
};
class FakeAeadKeyManager
: public KeyTypeManager<AesGcmKey, AesGcmKeyFormat, List<Aead>> {
public:
class AeadFactory : public PrimitiveFactory<Aead> {
public:
explicit AeadFactory(absl::string_view key_type) : key_type_(key_type) {}
util::StatusOr<std::unique_ptr<Aead>> Create(
const AesGcmKey& key) const override {
return {absl::make_unique<test::DummyAead>(key_type_)};
}
private:
const std::string key_type_;
};
explicit FakeAeadKeyManager(absl::string_view key_type)
: KeyTypeManager(absl::make_unique<AeadFactory>(key_type)),
key_type_(key_type) {}
google::crypto::tink::KeyData::KeyMaterialType key_material_type()
const override {
return google::crypto::tink::KeyData::SYMMETRIC;
}
uint32_t get_version() const override { return 0; }
const std::string& get_key_type() const override { return key_type_; }
crypto::tink::util::Status ValidateKey(const AesGcmKey& key) const override {
return util::OkStatus();
}
crypto::tink::util::Status ValidateKeyFormat(
const AesGcmKeyFormat& key_format) const override {
return util::OkStatus();
}
crypto::tink::util::StatusOr<AesGcmKey> CreateKey(
const AesGcmKeyFormat& key_format) const override {
return AesGcmKey();
}
crypto::tink::util::StatusOr<AesGcmKey> DeriveKey(
const AesGcmKeyFormat& key_format,
InputStream* input_stream) const override {
return AesGcmKey();
}
private:
const std::string key_type_;
};
TEST_F(KeysetHandleBuilderTest, BuildWithAnnotations) {
const absl::flat_hash_map<std::string, std::string> kAnnotations = {
{"key1", "value1"}, {"key2", "value2"}};
util::StatusOr<AesGcmParameters> aes_128_gcm =
AesGcmParameters::Builder()
.SetKeySizeInBytes(16)
.SetIvSizeInBytes(12)
.SetTagSizeInBytes(16)
.SetVariant(AesGcmParameters::Variant::kTink)
.Build();
ASSERT_THAT(aes_128_gcm, IsOk());
util::StatusOr<KeysetHandle> keyset_handle =
KeysetHandleBuilder()
.AddEntry(KeysetHandleBuilder::Entry::CreateFromCopyableParams(
*aes_128_gcm, crypto::tink::KeyStatus::kEnabled,
/*is_primary=*/true))
.SetMonitoringAnnotations(kAnnotations)
.Build();
ASSERT_THAT(keyset_handle, IsOk());
// In order to validate annotations are set correctly, we need acceess to the
// generated primitive set, which is populated by KeysetWrapperImpl and passed
// to the primitive wrapper. We thus register a mock primitive wrapper for
// Aead so that we can copy the annotations and later check them.
auto primitive_wrapper = absl::make_unique<MockAeadPrimitiveWrapper>();
absl::flat_hash_map<std::string, std::string> generated_annotations;
EXPECT_CALL(*primitive_wrapper, Wrap(_))
.WillOnce(
[&generated_annotations](
std::unique_ptr<PrimitiveSet<Aead>> generated_primitive_set) {
generated_annotations = generated_primitive_set->get_annotations();
std::unique_ptr<Aead> aead = absl::make_unique<test::DummyAead>("");
return aead;
});
Registry::Reset();
ASSERT_THAT(Registry::RegisterPrimitiveWrapper(std::move(primitive_wrapper)),
IsOk());
ASSERT_THAT(Registry::RegisterKeyTypeManager(
absl::make_unique<FakeAeadKeyManager>(
"type.googleapis.com/google.crypto.tink.AesGcmKey"),
/*new_key_allowed=*/true),
IsOk());
ASSERT_THAT(
keyset_handle->GetPrimitive<crypto::tink::Aead>(ConfigGlobalRegistry()),
IsOk());
EXPECT_EQ(generated_annotations, kAnnotations);
// This is needed to cleanup mocks.
Registry::Reset();
}
} // namespace
} // namespace tink
} // namespace crypto