From 6cac543614896605f3930c1e9a06aded26856376 Mon Sep 17 00:00:00 2001 From: William Conner Date: Fri, 13 Dec 2024 07:29:46 -0800 Subject: [PATCH] Add internal proto serialization library for PRF-based key derivation parameters. PiperOrigin-RevId: 705878021 Change-Id: I22d9d9d72c0d94793c70f719603293bb39ebd93d --- tink/keyderivation/internal/BUILD.bazel | 52 +++ tink/keyderivation/internal/CMakeLists.txt | 51 +++ ...key_derivation_proto_serialization_impl.cc | 203 +++++++++ ..._key_derivation_proto_serialization_impl.h | 45 ++ ...erivation_proto_serialization_impl_test.cc | 403 ++++++++++++++++++ 5 files changed, 754 insertions(+) create mode 100644 tink/keyderivation/internal/prf_based_key_derivation_proto_serialization_impl.cc create mode 100644 tink/keyderivation/internal/prf_based_key_derivation_proto_serialization_impl.h create mode 100644 tink/keyderivation/internal/prf_based_key_derivation_proto_serialization_impl_test.cc diff --git a/tink/keyderivation/internal/BUILD.bazel b/tink/keyderivation/internal/BUILD.bazel index 8fb27502..d661839e 100644 --- a/tink/keyderivation/internal/BUILD.bazel +++ b/tink/keyderivation/internal/BUILD.bazel @@ -285,3 +285,55 @@ cc_test( "@com_google_googletest//:gtest_main", ], ) + +cc_library( + name = "prf_based_key_derivation_proto_serialization_impl", + srcs = ["prf_based_key_derivation_proto_serialization_impl.cc"], + hdrs = ["prf_based_key_derivation_proto_serialization_impl.h"], + include_prefix = "tink/keyderivation/internal", + deps = [ + "//proto:prf_based_deriver_cc_proto", + "//proto:tink_cc_proto", + "//tink:parameters", + "//tink/internal:global_serialization_registry", + "//tink/internal:mutable_serialization_registry", + "//tink/internal:parameters_parser", + "//tink/internal:parameters_serializer", + "//tink/internal:proto_parameters_serialization", + "//tink/internal:serialization", + "//tink/internal:serialization_registry", + "//tink/keyderivation:prf_based_key_derivation_parameters", + "//tink/prf:prf_parameters", + "//tink/util:status", + "//tink/util:statusor", + "@com_google_absl//absl/log:check", + "@com_google_absl//absl/status", + "@com_google_absl//absl/strings:string_view", + ], +) + +cc_test( + name = "prf_based_key_derivation_proto_serialization_impl_test", + srcs = ["prf_based_key_derivation_proto_serialization_impl_test.cc"], + deps = [ + ":prf_based_key_derivation_proto_serialization_impl", + "//proto:aes_cmac_prf_cc_proto", + "//proto:prf_based_deriver_cc_proto", + "//proto:tink_cc_proto", + "//proto:xchacha20_poly1305_cc_proto", + "//tink:parameters", + "//tink/aead:xchacha20_poly1305_parameters", + "//tink/internal:mutable_serialization_registry", + "//tink/internal:proto_parameters_serialization", + "//tink/internal:serialization", + "//tink/internal:serialization_registry", + "//tink/keyderivation:prf_based_key_derivation_parameters", + "//tink/prf:aes_cmac_prf_parameters", + "//tink/util:statusor", + "//tink/util:test_matchers", + "@com_google_absl//absl/log:check", + "@com_google_absl//absl/status", + "@com_google_absl//absl/strings:string_view", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/tink/keyderivation/internal/CMakeLists.txt b/tink/keyderivation/internal/CMakeLists.txt index 8a053814..0c874d54 100644 --- a/tink/keyderivation/internal/CMakeLists.txt +++ b/tink/keyderivation/internal/CMakeLists.txt @@ -279,3 +279,54 @@ tink_cc_test( tink::util::test_util tink::proto::tink_cc_proto ) + +tink_cc_library( + NAME prf_based_key_derivation_proto_serialization_impl + SRCS + prf_based_key_derivation_proto_serialization_impl.cc + prf_based_key_derivation_proto_serialization_impl.h + DEPS + absl::check + absl::status + absl::string_view + tink::core::parameters + tink::internal::global_serialization_registry + tink::internal::mutable_serialization_registry + tink::internal::parameters_parser + tink::internal::parameters_serializer + tink::internal::proto_parameters_serialization + tink::internal::serialization + tink::internal::serialization_registry + tink::keyderivation::prf_based_key_derivation_parameters + tink::prf::prf_parameters + tink::util::status + tink::util::statusor + tink::proto::prf_based_deriver_cc_proto + tink::proto::tink_cc_proto +) + +tink_cc_test( + NAME prf_based_key_derivation_proto_serialization_impl_test + SRCS + prf_based_key_derivation_proto_serialization_impl_test.cc + DEPS + tink::keyderivation::internal::prf_based_key_derivation_proto_serialization_impl + gmock + absl::check + absl::status + absl::string_view + tink::core::parameters + tink::aead::xchacha20_poly1305_parameters + tink::internal::mutable_serialization_registry + tink::internal::proto_parameters_serialization + tink::internal::serialization + tink::internal::serialization_registry + tink::keyderivation::prf_based_key_derivation_parameters + tink::prf::aes_cmac_prf_parameters + tink::util::statusor + tink::util::test_matchers + tink::proto::aes_cmac_prf_cc_proto + tink::proto::prf_based_deriver_cc_proto + tink::proto::tink_cc_proto + tink::proto::xchacha20_poly1305_cc_proto +) diff --git a/tink/keyderivation/internal/prf_based_key_derivation_proto_serialization_impl.cc b/tink/keyderivation/internal/prf_based_key_derivation_proto_serialization_impl.cc new file mode 100644 index 00000000..2b0f5f80 --- /dev/null +++ b/tink/keyderivation/internal/prf_based_key_derivation_proto_serialization_impl.cc @@ -0,0 +1,203 @@ +// Copyright 2024 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/keyderivation/internal/prf_based_key_derivation_proto_serialization_impl.h" + +#include + +#include "absl/log/check.h" +#include "absl/status/status.h" +#include "absl/strings/string_view.h" +#include "tink/internal/global_serialization_registry.h" +#include "tink/internal/mutable_serialization_registry.h" +#include "tink/internal/parameters_parser.h" +#include "tink/internal/parameters_serializer.h" +#include "tink/internal/proto_parameters_serialization.h" +#include "tink/internal/serialization.h" +#include "tink/internal/serialization_registry.h" +#include "tink/keyderivation/prf_based_key_derivation_parameters.h" +#include "tink/parameters.h" +#include "tink/prf/prf_parameters.h" +#include "tink/util/status.h" +#include "tink/util/statusor.h" +#include "proto/prf_based_deriver.pb.h" +#include "proto/tink.pb.h" + +namespace crypto { +namespace tink { +namespace internal { +namespace { + +using ::google::crypto::tink::KeyTemplate; +using ::google::crypto::tink::PrfBasedDeriverKeyFormat; + +using PrfBasedKeyDerivationProtoParametersParserImpl = + ParametersParserImpl; +using PrfBasedKeyDerivationProtoParametersSerializerImpl = + ParametersSerializerImpl; + +const absl::string_view kTypeUrl = + "type.googleapis.com/google.crypto.tink.PrfBasedDeriverKey"; + +util::StatusOr> ParametersFromKeyTemplate( + const KeyTemplate& key_template) { + util::StatusOr proto_params_serialization = + ProtoParametersSerialization::Create(key_template); + if (!proto_params_serialization.ok()) { + return proto_params_serialization.status(); + } + return GlobalSerializationRegistry().ParseParameters( + *proto_params_serialization); +} + +util::StatusOr ParametersToKeyTemplate( + const Parameters& parameters) { + util::StatusOr> serialization = + GlobalSerializationRegistry() + .SerializeParameters(parameters); + if (!serialization.ok()) { + return serialization.status(); + } + + const ProtoParametersSerialization* proto_serialization = + dynamic_cast(serialization->get()); + if (proto_serialization == nullptr) { + return util::Status(absl::StatusCode::kInternal, + "Failed to serialize proto parameters."); + } + + return proto_serialization->GetKeyTemplate(); +} + +util::StatusOr ParseParameters( + const ProtoParametersSerialization& serialization) { + if (serialization.GetKeyTemplate().type_url() != kTypeUrl) { + return util::Status( + absl::StatusCode::kInvalidArgument, + "Wrong type URL when parsing PrfBasedKeyDerivationParameters."); + } + + PrfBasedDeriverKeyFormat proto_key_format; + if (!proto_key_format.ParseFromString( + serialization.GetKeyTemplate().value())) { + return util::Status(absl::StatusCode::kInvalidArgument, + "Failed to parse PrfBasedKeyDerivationKeyFormat proto"); + } + + if (serialization.GetKeyTemplate().output_prefix_type() != + proto_key_format.params().derived_key_template().output_prefix_type()) { + return util::Status( + absl::StatusCode::kInvalidArgument, + "Parsed output prefix type must match derived key output prefix type."); + } + + util::StatusOr> derived_key_parameters = + ParametersFromKeyTemplate( + proto_key_format.params().derived_key_template()); + if (!derived_key_parameters.ok()) { + return derived_key_parameters.status(); + } + + util::StatusOr> parameters = + ParametersFromKeyTemplate(proto_key_format.prf_key_template()); + if (!parameters.ok()) { + return parameters.status(); + } + + const PrfParameters* prf_parameters = + dynamic_cast(parameters->get()); + if (prf_parameters == nullptr) { + return absl::Status( + absl::StatusCode::kInvalidArgument, + "Non-PRF parameters stored in the `prf_key_template` field."); + } + + return PrfBasedKeyDerivationParameters::Builder() + .SetPrfParameters(*prf_parameters) + .SetDerivedKeyParameters(**derived_key_parameters) + .Build(); +} + +util::StatusOr SerializeParameters( + const PrfBasedKeyDerivationParameters& parameters) { + util::StatusOr prf_key_template = + ParametersToKeyTemplate(parameters.GetPrfParameters()); + if (!prf_key_template.ok()) { + return prf_key_template.status(); + } + + util::StatusOr derived_key_template = + ParametersToKeyTemplate(parameters.GetDerivedKeyParameters()); + if (!derived_key_template.ok()) { + return derived_key_template.status(); + } + + PrfBasedDeriverKeyFormat proto_key_format; + *proto_key_format.mutable_prf_key_template() = *prf_key_template; + *proto_key_format.mutable_params()->mutable_derived_key_template() = + *derived_key_template; + + return ProtoParametersSerialization::Create( + kTypeUrl, derived_key_template->output_prefix_type(), + proto_key_format.SerializeAsString()); +} + +PrfBasedKeyDerivationProtoParametersParserImpl* +PrfBasedKeyDerivationProtoParametersParser() { + static auto* parser = new PrfBasedKeyDerivationProtoParametersParserImpl( + kTypeUrl, ParseParameters); + return parser; +} + +PrfBasedKeyDerivationProtoParametersSerializerImpl* +PrfBasedKeyDerivationProtoParametersSerializer() { + static auto* serializer = + new PrfBasedKeyDerivationProtoParametersSerializerImpl( + kTypeUrl, SerializeParameters); + return serializer; +} + +} // namespace + +util::Status RegisterPrfBasedKeyDerivationProtoSerializationWithMutableRegistry( + MutableSerializationRegistry& registry) { + util::Status status = registry.RegisterParametersParser( + PrfBasedKeyDerivationProtoParametersParser()); + if (!status.ok()) { + return status; + } + + return registry.RegisterParametersSerializer( + PrfBasedKeyDerivationProtoParametersSerializer()); +} + +util::Status RegisterPrfBasedKeyDerivationProtoSerializationWithRegistryBuilder( + SerializationRegistry::Builder& builder) { + util::Status status = builder.RegisterParametersParser( + PrfBasedKeyDerivationProtoParametersParser()); + if (!status.ok()) { + return status; + } + + return builder.RegisterParametersSerializer( + PrfBasedKeyDerivationProtoParametersSerializer()); +} + +} // namespace internal +} // namespace tink +} // namespace crypto diff --git a/tink/keyderivation/internal/prf_based_key_derivation_proto_serialization_impl.h b/tink/keyderivation/internal/prf_based_key_derivation_proto_serialization_impl.h new file mode 100644 index 00000000..45a4e6de --- /dev/null +++ b/tink/keyderivation/internal/prf_based_key_derivation_proto_serialization_impl.h @@ -0,0 +1,45 @@ +// Copyright 2024 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. +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef TINK_KEYDERIVATION_INTERNAL_PRF_BASED_KEY_DERIVATION_PROTO_SERIALIZATION_IMPL_H_ +#define TINK_KEYDERIVATION_INTERNAL_PRF_BASED_KEY_DERIVATION_PROTO_SERIALIZATION_IMPL_H_ + +#include "tink/internal/mutable_serialization_registry.h" +#include "tink/internal/serialization_registry.h" +#include "tink/util/status.h" + +namespace crypto { +namespace tink { +namespace internal { + +// Registers proto parsers and serializers for PRF-based key derivation +// parameters and keys into specified mutable serialization `registry`. +crypto::tink::util::Status +RegisterPrfBasedKeyDerivationProtoSerializationWithMutableRegistry( + MutableSerializationRegistry& registry); + +// Registers proto parsers and serializers for PRF-based key derivation +// parameters and keys into specified immutable serialization registry +// `builder`. +crypto::tink::util::Status +RegisterPrfBasedKeyDerivationProtoSerializationWithRegistryBuilder( + SerializationRegistry::Builder& builder); + +} // namespace internal +} // namespace tink +} // namespace crypto + +#endif // TINK_KEYDERIVATION_INTERNAL_PRF_BASED_KEY_DERIVATION_PROTO_SERIALIZATION_IMPL_H_ diff --git a/tink/keyderivation/internal/prf_based_key_derivation_proto_serialization_impl_test.cc b/tink/keyderivation/internal/prf_based_key_derivation_proto_serialization_impl_test.cc new file mode 100644 index 00000000..a1776364 --- /dev/null +++ b/tink/keyderivation/internal/prf_based_key_derivation_proto_serialization_impl_test.cc @@ -0,0 +1,403 @@ +// Copyright 2024 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/keyderivation/internal/prf_based_key_derivation_proto_serialization_impl.h" + +#include +#include + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "absl/log/check.h" +#include "absl/status/status.h" +#include "absl/strings/string_view.h" +#include "tink/aead/xchacha20_poly1305_parameters.h" +#include "tink/internal/mutable_serialization_registry.h" +#include "tink/internal/proto_parameters_serialization.h" +#include "tink/internal/serialization.h" +#include "tink/internal/serialization_registry.h" +#include "tink/keyderivation/prf_based_key_derivation_parameters.h" +#include "tink/parameters.h" +#include "tink/prf/aes_cmac_prf_parameters.h" +#include "tink/util/statusor.h" +#include "tink/util/test_matchers.h" +#include "proto/aes_cmac_prf.pb.h" +#include "proto/prf_based_deriver.pb.h" +#include "proto/tink.pb.h" +#include "proto/xchacha20_poly1305.pb.h" + +namespace crypto { +namespace tink { +namespace internal { +namespace { + +using ::crypto::tink::test::IsOk; +using ::crypto::tink::test::StatusIs; +using ::google::crypto::tink::AesCmacPrfKeyFormat; +using ::google::crypto::tink::KeyTemplate; +using ::google::crypto::tink::OutputPrefixType; +using ::google::crypto::tink::PrfBasedDeriverKeyFormat; +using ::google::crypto::tink::PrfBasedDeriverParams; +using ::google::crypto::tink::XChaCha20Poly1305KeyFormat; +using ::testing::Eq; +using ::testing::HasSubstr; +using ::testing::IsTrue; +using ::testing::NotNull; + +constexpr absl::string_view kTypeUrl = + "type.googleapis.com/google.crypto.tink.PrfBasedDeriverKey"; +constexpr absl::string_view kPrfKeyTypeUrl = + "type.googleapis.com/google.crypto.tink.AesCmacPrfKey"; +constexpr absl::string_view kDerivedKeyTypeUrl = + "type.googleapis.com/google.crypto.tink.XChaCha20Poly1305Key"; +constexpr absl::string_view kPrfKeyValue = "0123456789abcdef"; + +KeyTemplate GetAesCmacPrfKeyTemplate() { + AesCmacPrfKeyFormat key_format; + key_format.set_version(0); + key_format.set_key_size(kPrfKeyValue.size()); + KeyTemplate key_template; + key_template.set_type_url(kPrfKeyTypeUrl); + key_template.set_value(key_format.SerializeAsString()); + key_template.set_output_prefix_type(OutputPrefixType::RAW); + return key_template; +} + +AesCmacPrfParameters GetAesCmacPrfParameters() { + util::StatusOr parameters = + AesCmacPrfParameters::Create(kPrfKeyValue.size()); + CHECK_OK(parameters); + return *parameters; +} + +KeyTemplate GetXChaCha20Poly1305KeyTemplate() { + XChaCha20Poly1305KeyFormat key_format; + key_format.set_version(0); + KeyTemplate key_template; + key_template.set_type_url(kDerivedKeyTypeUrl); + key_template.set_value(key_format.SerializeAsString()); + key_template.set_output_prefix_type(OutputPrefixType::TINK); + return key_template; +} + +XChaCha20Poly1305Parameters GetXChaCha20Poly1305Parameters() { + util::StatusOr parameters = + XChaCha20Poly1305Parameters::Create( + XChaCha20Poly1305Parameters::Variant::kTink); + CHECK_OK(parameters); + return *parameters; +} + +TEST(PrfBasedKeyDerivationProtoSerializationTest, + RegisterTwiceSucceedsWithMutableRegistry) { + MutableSerializationRegistry registry; + ASSERT_THAT( + RegisterPrfBasedKeyDerivationProtoSerializationWithMutableRegistry( + registry), + IsOk()); + ASSERT_THAT( + RegisterPrfBasedKeyDerivationProtoSerializationWithMutableRegistry( + registry), + IsOk()); +} + +TEST(PrfBasedKeyDerivationProtoSerializationTest, + RegisterTwiceSucceedsWithRegistryBuilder) { + // TODO: b/378091229 - Consider disallowing duplicate registrations. + SerializationRegistry::Builder builder; + ASSERT_THAT( + RegisterPrfBasedKeyDerivationProtoSerializationWithRegistryBuilder( + builder), + IsOk()); + ASSERT_THAT( + RegisterPrfBasedKeyDerivationProtoSerializationWithRegistryBuilder( + builder), + IsOk()); +} + +TEST(PrfBasedKeyDerivationProtoSerializationTest, + ParseParametersWithMutableRegistry) { + MutableSerializationRegistry registry; + ASSERT_THAT( + RegisterPrfBasedKeyDerivationProtoSerializationWithMutableRegistry( + registry), + IsOk()); + + KeyTemplate derived_key_template = GetXChaCha20Poly1305KeyTemplate(); + + PrfBasedDeriverKeyFormat key_format_proto; + *key_format_proto.mutable_prf_key_template() = GetAesCmacPrfKeyTemplate(); + PrfBasedDeriverParams prf_based_deriver_params; + *prf_based_deriver_params.mutable_derived_key_template() = + derived_key_template; + *key_format_proto.mutable_params() = prf_based_deriver_params; + + util::StatusOr serialization = + internal::ProtoParametersSerialization::Create( + kTypeUrl, derived_key_template.output_prefix_type(), + key_format_proto.SerializeAsString()); + ASSERT_THAT(serialization, IsOk()); + + util::StatusOr> params = + registry.ParseParameters(*serialization); + ASSERT_THAT(params, IsOk()); + EXPECT_THAT((*params)->HasIdRequirement(), IsTrue()); + + const PrfBasedKeyDerivationParameters* prf_based_deriver_parameters = + dynamic_cast(params->get()); + ASSERT_THAT(prf_based_deriver_parameters, NotNull()); + + EXPECT_THAT(prf_based_deriver_parameters->GetPrfParameters(), + Eq(GetAesCmacPrfParameters())); + EXPECT_THAT(prf_based_deriver_parameters->GetDerivedKeyParameters(), + Eq(GetXChaCha20Poly1305Parameters())); +} + +TEST(PrfBasedKeyDerivationProtoSerializationTest, + ParseParametersWithRegistryBuilder) { + SerializationRegistry::Builder builder; + ASSERT_THAT( + RegisterPrfBasedKeyDerivationProtoSerializationWithRegistryBuilder( + builder), + IsOk()); + SerializationRegistry registry = std::move(builder).Build(); + + KeyTemplate derived_key_template = GetXChaCha20Poly1305KeyTemplate(); + + PrfBasedDeriverKeyFormat key_format_proto; + *key_format_proto.mutable_prf_key_template() = GetAesCmacPrfKeyTemplate(); + PrfBasedDeriverParams prf_based_deriver_params; + *prf_based_deriver_params.mutable_derived_key_template() = + derived_key_template; + *key_format_proto.mutable_params() = prf_based_deriver_params; + + util::StatusOr serialization = + internal::ProtoParametersSerialization::Create( + kTypeUrl, derived_key_template.output_prefix_type(), + key_format_proto.SerializeAsString()); + ASSERT_THAT(serialization, IsOk()); + + util::StatusOr> params = + registry.ParseParameters(*serialization); + ASSERT_THAT(params, IsOk()); + EXPECT_THAT((*params)->HasIdRequirement(), IsTrue()); + + const PrfBasedKeyDerivationParameters* prf_based_deriver_parameters = + dynamic_cast(params->get()); + ASSERT_THAT(prf_based_deriver_parameters, NotNull()); + + EXPECT_THAT(prf_based_deriver_parameters->GetPrfParameters(), + Eq(GetAesCmacPrfParameters())); + EXPECT_THAT(prf_based_deriver_parameters->GetDerivedKeyParameters(), + Eq(GetXChaCha20Poly1305Parameters())); +} + +TEST(PrfBasedKeyDerivationProtoSerializationTest, + ParseParametersWithInvalidSerialization) { + MutableSerializationRegistry registry; + ASSERT_THAT( + RegisterPrfBasedKeyDerivationProtoSerializationWithMutableRegistry( + registry), + IsOk()); + + util::StatusOr serialization = + internal::ProtoParametersSerialization::Create( + kTypeUrl, OutputPrefixType::RAW, "invalid_serialization"); + ASSERT_THAT(serialization, IsOk()); + + util::StatusOr> params = + registry.ParseParameters(*serialization); + EXPECT_THAT( + params.status(), + StatusIs( + absl::StatusCode::kInvalidArgument, + HasSubstr("Failed to parse PrfBasedKeyDerivationKeyFormat proto"))); +} + +TEST(PrfBasedKeyDerivationProtoSerializationTest, + ParseParametersWithMismatchedOutputPrefix) { + MutableSerializationRegistry registry; + ASSERT_THAT( + RegisterPrfBasedKeyDerivationProtoSerializationWithMutableRegistry( + registry), + IsOk()); + + PrfBasedDeriverKeyFormat key_format_proto; + *key_format_proto.mutable_prf_key_template() = GetAesCmacPrfKeyTemplate(); + PrfBasedDeriverParams prf_based_deriver_params; + *prf_based_deriver_params.mutable_derived_key_template() = + GetXChaCha20Poly1305KeyTemplate(); + *key_format_proto.mutable_params() = prf_based_deriver_params; + + util::StatusOr serialization = + internal::ProtoParametersSerialization::Create( + kTypeUrl, OutputPrefixType::RAW, + key_format_proto.SerializeAsString()); + ASSERT_THAT(serialization, IsOk()); + + util::StatusOr> params = + registry.ParseParameters(*serialization); + EXPECT_THAT(params.status(), + StatusIs(absl::StatusCode::kInvalidArgument, + HasSubstr("Parsed output prefix type must match derived " + "key output prefix type"))); +} + +TEST(PrfBasedKeyDerivationProtoSerializationTest, + ParseParametersWithUnknownOutputPrefix) { + MutableSerializationRegistry registry; + ASSERT_THAT( + RegisterPrfBasedKeyDerivationProtoSerializationWithMutableRegistry( + registry), + IsOk()); + + KeyTemplate derived_key_template = GetXChaCha20Poly1305KeyTemplate(); + derived_key_template.set_output_prefix_type(OutputPrefixType::UNKNOWN_PREFIX); + + PrfBasedDeriverKeyFormat key_format_proto; + *key_format_proto.mutable_prf_key_template() = GetAesCmacPrfKeyTemplate(); + PrfBasedDeriverParams prf_based_deriver_params; + *prf_based_deriver_params.mutable_derived_key_template() = + derived_key_template; + *key_format_proto.mutable_params() = prf_based_deriver_params; + + util::StatusOr serialization = + internal::ProtoParametersSerialization::Create( + kTypeUrl, OutputPrefixType::UNKNOWN_PREFIX, + key_format_proto.SerializeAsString()); + ASSERT_THAT(serialization, IsOk()); + + util::StatusOr> params = + registry.ParseParameters(*serialization); + EXPECT_THAT( + params.status(), + StatusIs( + absl::StatusCode::kInvalidArgument, + HasSubstr( + "Could not determine XChaCha20Poly1305Parameters::Variant"))); +} + +TEST(PrfBasedKeyDerivationProtoSerializationTest, + ParseParametersWithInvalidPrfKeyTemplate) { + MutableSerializationRegistry registry; + ASSERT_THAT( + RegisterPrfBasedKeyDerivationProtoSerializationWithMutableRegistry( + registry), + IsOk()); + + PrfBasedDeriverKeyFormat key_format_proto; + *key_format_proto.mutable_prf_key_template() = + GetXChaCha20Poly1305KeyTemplate(); + PrfBasedDeriverParams prf_based_deriver_params; + *prf_based_deriver_params.mutable_derived_key_template() = + GetXChaCha20Poly1305KeyTemplate(); + *key_format_proto.mutable_params() = prf_based_deriver_params; + + util::StatusOr serialization = + internal::ProtoParametersSerialization::Create( + kTypeUrl, OutputPrefixType::TINK, + key_format_proto.SerializeAsString()); + ASSERT_THAT(serialization, IsOk()); + + util::StatusOr> params = + registry.ParseParameters(*serialization); + EXPECT_THAT( + params.status(), + StatusIs( + absl::StatusCode::kInvalidArgument, + HasSubstr( + "Non-PRF parameters stored in the `prf_key_template` field"))); +} + +TEST(PrfBasedKeyDerivationProtoSerializationTest, + SerializeParametersWithMutableRegistry) { + MutableSerializationRegistry registry; + ASSERT_THAT( + RegisterPrfBasedKeyDerivationProtoSerializationWithMutableRegistry( + registry), + IsOk()); + + util::StatusOr parameters = + PrfBasedKeyDerivationParameters::Builder() + .SetPrfParameters(GetAesCmacPrfParameters()) + .SetDerivedKeyParameters(GetXChaCha20Poly1305Parameters()) + .Build(); + ASSERT_THAT(parameters, IsOk()); + + util::StatusOr> serialization = + registry.SerializeParameters( + *parameters); + ASSERT_THAT(serialization, IsOk()); + + const internal::ProtoParametersSerialization* proto_serialization = + dynamic_cast( + serialization->get()); + ASSERT_THAT(proto_serialization, NotNull()); + EXPECT_THAT(proto_serialization->GetKeyTemplate().type_url(), Eq(kTypeUrl)); + EXPECT_THAT(proto_serialization->GetKeyTemplate().output_prefix_type(), + Eq(OutputPrefixType::TINK)); + + PrfBasedDeriverKeyFormat key_format; + ASSERT_THAT( + key_format.ParseFromString(proto_serialization->GetKeyTemplate().value()), + IsTrue()); + EXPECT_THAT(key_format.prf_key_template().type_url(), Eq(kPrfKeyTypeUrl)); + EXPECT_THAT(key_format.params().derived_key_template().type_url(), + Eq(kDerivedKeyTypeUrl)); +} + +TEST(PrfBasedKeyDerivationProtoSerializationTest, + SerializeParametersWithRegistryBuilder) { + SerializationRegistry::Builder builder; + ASSERT_THAT( + RegisterPrfBasedKeyDerivationProtoSerializationWithRegistryBuilder( + builder), + IsOk()); + SerializationRegistry registry = std::move(builder).Build(); + + util::StatusOr parameters = + PrfBasedKeyDerivationParameters::Builder() + .SetPrfParameters(GetAesCmacPrfParameters()) + .SetDerivedKeyParameters(GetXChaCha20Poly1305Parameters()) + .Build(); + ASSERT_THAT(parameters, IsOk()); + + util::StatusOr> serialization = + registry.SerializeParameters( + *parameters); + ASSERT_THAT(serialization, IsOk()); + + const internal::ProtoParametersSerialization* proto_serialization = + dynamic_cast( + serialization->get()); + ASSERT_THAT(proto_serialization, NotNull()); + EXPECT_THAT(proto_serialization->GetKeyTemplate().type_url(), Eq(kTypeUrl)); + EXPECT_THAT(proto_serialization->GetKeyTemplate().output_prefix_type(), + Eq(OutputPrefixType::TINK)); + + PrfBasedDeriverKeyFormat key_format; + ASSERT_THAT( + key_format.ParseFromString(proto_serialization->GetKeyTemplate().value()), + IsTrue()); + EXPECT_THAT(key_format.prf_key_template().type_url(), Eq(kPrfKeyTypeUrl)); + EXPECT_THAT(key_format.params().derived_key_template().type_url(), + Eq(kDerivedKeyTypeUrl)); +} + +} // namespace +} // namespace internal +} // namespace tink +} // namespace crypto