From 4b887da0f331ca6d5aacb99774e6d87e8cef3914 Mon Sep 17 00:00:00 2001 From: William Conner Date: Wed, 18 Dec 2024 10:02:38 -0800 Subject: [PATCH] Register PRF-based key derivation proto serialization. PiperOrigin-RevId: 707586106 Change-Id: Ieab1caa2f62f779111d1e5cd6edae1fe28a36770 --- tink/keyderivation/BUILD.bazel | 24 ++ tink/keyderivation/CMakeLists.txt | 24 ++ tink/keyderivation/key_derivation_config.cc | 6 + .../key_derivation_config_test.cc | 224 +++++++++++++++++- 4 files changed, 275 insertions(+), 3 deletions(-) diff --git a/tink/keyderivation/BUILD.bazel b/tink/keyderivation/BUILD.bazel index 348e4fa0..9148db5a 100644 --- a/tink/keyderivation/BUILD.bazel +++ b/tink/keyderivation/BUILD.bazel @@ -44,6 +44,7 @@ cc_library( visibility = ["//visibility:public"], deps = [ ":keyset_deriver_wrapper", + ":prf_based_key_derivation_proto_serialization", "//tink:registry", "//tink/config:tink_fips", "//tink/keyderivation/internal:prf_based_deriver_key_manager", @@ -169,18 +170,41 @@ cc_test( ":key_derivation_config", ":key_derivation_key_templates", ":keyset_deriver", + ":prf_based_key_derivation_key", + ":prf_based_key_derivation_parameters", + "//proto:aes_cmac_prf_cc_proto", + "//proto:prf_based_deriver_cc_proto", "//proto:tink_cc_proto", + "//proto:xchacha20_poly1305_cc_proto", "//tink:aead", + "//tink:key_status", "//tink:keyset_handle", + "//tink:parameters", + "//tink:partial_key_access", + "//tink:proto_parameters_format", "//tink:registry", + "//tink:restricted_data", "//tink/aead:aead_config", "//tink/aead:aead_key_templates", "//tink/aead:aes_gcm_key_manager", + "//tink/aead:xchacha20_poly1305_parameters", "//tink/config:global_registry", + "//tink/internal:fips_utils", + "//tink/internal:internal_insecure_secret_key_access", + "//tink/internal:legacy_proto_key", + "//tink/internal:legacy_proto_parameters", + "//tink/internal:mutable_serialization_registry", + "//tink/keyderivation/internal:prf_based_deriver_key_manager", + "//tink/prf:aes_cmac_prf_key", + "//tink/prf:aes_cmac_prf_parameters", + "//tink/prf:prf_config", "//tink/prf:prf_key_templates", "//tink/util:statusor", "//tink/util:test_matchers", + "@com_google_absl//absl/log:check", "@com_google_absl//absl/memory", + "@com_google_absl//absl/status", + "@com_google_absl//absl/strings:string_view", "@com_google_googletest//:gtest_main", ], ) diff --git a/tink/keyderivation/CMakeLists.txt b/tink/keyderivation/CMakeLists.txt index 330eb4dd..cd74bd3c 100644 --- a/tink/keyderivation/CMakeLists.txt +++ b/tink/keyderivation/CMakeLists.txt @@ -39,6 +39,7 @@ tink_cc_library( key_derivation_config.h DEPS tink::keyderivation::keyset_deriver_wrapper + tink::keyderivation::prf_based_key_derivation_proto_serialization absl::memory tink::core::registry tink::config::tink_fips @@ -161,19 +162,42 @@ tink_cc_test( tink::keyderivation::key_derivation_config tink::keyderivation::key_derivation_key_templates tink::keyderivation::keyset_deriver + tink::keyderivation::prf_based_key_derivation_key + tink::keyderivation::prf_based_key_derivation_parameters gmock + absl::check absl::memory + absl::status + absl::string_view tink::core::aead + tink::core::key_status tink::core::keyset_handle + tink::core::parameters + tink::core::partial_key_access + tink::core::proto_parameters_format tink::core::registry + tink::core::restricted_data tink::aead::aead_config tink::aead::aead_key_templates tink::aead::aes_gcm_key_manager + tink::aead::xchacha20_poly1305_parameters tink::config::global_registry + tink::internal::fips_utils + tink::internal::internal_insecure_secret_key_access + tink::internal::legacy_proto_key + tink::internal::legacy_proto_parameters + tink::internal::mutable_serialization_registry + tink::keyderivation::internal::prf_based_deriver_key_manager + tink::prf::aes_cmac_prf_key + tink::prf::aes_cmac_prf_parameters + tink::prf::prf_config tink::prf::prf_key_templates 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 ) tink_cc_test( diff --git a/tink/keyderivation/key_derivation_config.cc b/tink/keyderivation/key_derivation_config.cc index fef7aaff..f5f83973 100644 --- a/tink/keyderivation/key_derivation_config.cc +++ b/tink/keyderivation/key_derivation_config.cc @@ -20,6 +20,7 @@ #include "tink/config/tink_fips.h" #include "tink/keyderivation/internal/prf_based_deriver_key_manager.h" #include "tink/keyderivation/keyset_deriver_wrapper.h" +#include "tink/keyderivation/prf_based_key_derivation_proto_serialization.h" #include "tink/prf/hkdf_prf_key_manager.h" #include "tink/registry.h" #include "tink/util/status.h" @@ -42,6 +43,11 @@ util::Status KeyDerivationConfig::Register() { return util::OkStatus(); } + status = RegisterPrfBasedKeyDerivationProtoSerialization(); + if (!status.ok()) { + return status; + } + // Register required key manager for PrfBasedDeriverKeyManager. status = Registry::RegisterKeyTypeManager( absl::make_unique(), true); diff --git a/tink/keyderivation/key_derivation_config_test.cc b/tink/keyderivation/key_derivation_config_test.cc index 97452137..27d1f02c 100644 --- a/tink/keyderivation/key_derivation_config_test.cc +++ b/tink/keyderivation/key_derivation_config_test.cc @@ -21,32 +21,79 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "absl/log/check.h" #include "absl/memory/memory.h" +#include "absl/status/status.h" +#include "absl/strings/string_view.h" #include "tink/aead.h" #include "tink/aead/aead_config.h" #include "tink/aead/aead_key_templates.h" #include "tink/aead/aes_gcm_key_manager.h" +#include "tink/aead/xchacha20_poly1305_parameters.h" #include "tink/config/global_registry.h" +#include "tink/internal/fips_utils.h" +#include "tink/internal/internal_insecure_secret_key_access.h" +#include "tink/internal/legacy_proto_key.h" +#include "tink/internal/legacy_proto_parameters.h" +#include "tink/internal/mutable_serialization_registry.h" +#include "tink/key_status.h" +#include "tink/keyderivation/internal/prf_based_deriver_key_manager.h" #include "tink/keyderivation/key_derivation_key_templates.h" #include "tink/keyderivation/keyset_deriver.h" +#include "tink/keyderivation/prf_based_key_derivation_key.h" +#include "tink/keyderivation/prf_based_key_derivation_parameters.h" #include "tink/keyset_handle.h" +#include "tink/parameters.h" +#include "tink/partial_key_access.h" +#include "tink/prf/aes_cmac_prf_key.h" +#include "tink/prf/aes_cmac_prf_parameters.h" +#include "tink/prf/prf_config.h" #include "tink/prf/prf_key_templates.h" +#include "tink/proto_parameters_format.h" #include "tink/registry.h" +#include "tink/restricted_data.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::HasSubstr; using ::testing::Not; +using ::testing::NotNull; +using ::testing::Test; + +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 = "0123456789abcdef0123456789abcdef"; -TEST(KeyDerivationConfigTest, Register) { - Registry::Reset(); +class KeyDerivationConfigTest : public Test { + protected: + void SetUp() override { + Registry::Reset(); + internal::MutableSerializationRegistry::GlobalInstance().Reset(); + } +}; +TEST_F(KeyDerivationConfigTest, Register) { EXPECT_THAT(KeyDerivationKeyTemplates::CreatePrfBasedKeyTemplate( PrfKeyTemplates::HkdfSha256(), AeadKeyTemplates::Aes256Gcm()), Not(IsOk())); @@ -85,6 +132,177 @@ TEST(KeyDerivationConfigTest, Register) { EXPECT_EQ(plaintext, *got); } +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; +} + +AesCmacPrfKey GetAesCmacPrfKey() { + util::StatusOr key = AesCmacPrfKey::Create( + RestrictedData(kPrfKeyValue, + internal::GetInsecureSecretKeyAccessInternal()), + GetPartialKeyAccess()); + CHECK_OK(key); + return *key; +} + +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_F(KeyDerivationConfigTest, + PrfBasedKeyDerivationProtoParamsSerializationRegistered) { + if (IsFipsModeEnabled()) { + GTEST_SKIP() << "Not supported in FIPS-only mode"; + } + + 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; + + KeyTemplate key_template; + key_template.set_type_url(kTypeUrl); + key_template.set_output_prefix_type( + derived_key_template.output_prefix_type()); + key_format_proto.SerializeToString(key_template.mutable_value()); + + util::StatusOr> proto_parameters = + ParseParametersFromProtoFormat(key_template.SerializeAsString()); + ASSERT_THAT(proto_parameters, IsOk()); + EXPECT_THAT( + dynamic_cast(proto_parameters->get()), + NotNull()); + + util::StatusOr parameters = + PrfBasedKeyDerivationParameters::Builder() + .SetPrfParameters(GetAesCmacPrfParameters()) + .SetDerivedKeyParameters(GetXChaCha20Poly1305Parameters()) + .Build(); + ASSERT_THAT(parameters, IsOk()); + EXPECT_THAT(SerializeParametersToProtoFormat(*parameters), + StatusIs(absl::StatusCode::kNotFound)); + + ASSERT_THAT(KeyDerivationConfig::Register(), IsOk()); + + util::StatusOr> parsed_parameters = + ParseParametersFromProtoFormat(key_template.SerializeAsString()); + ASSERT_THAT(parsed_parameters, IsOk()); + EXPECT_THAT( + dynamic_cast(parsed_parameters->get()), + NotNull()); + + EXPECT_THAT(SerializeParametersToProtoFormat(*parameters), IsOk()); +} + +TEST_F(KeyDerivationConfigTest, + PrfBasedKeyDerivationProtoKeySerializationRegistered) { + if (IsFipsModeEnabled()) { + GTEST_SKIP() << "Not supported in FIPS-only mode"; + } + + ASSERT_THAT(AeadConfig::Register(), IsOk()); // For XChaCha20Poly1305Key + ASSERT_THAT(PrfConfig::Register(), IsOk()); // For AesCmacPrfKey + + 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; + + KeyTemplate key_template; + key_template.set_type_url(kTypeUrl); + key_template.set_output_prefix_type( + derived_key_template.output_prefix_type()); + key_format_proto.SerializeToString(key_template.mutable_value()); + + // NOTE: No key generation config available yet for PrfBasedDeriver keys. + ASSERT_THAT( + Registry::RegisterKeyTypeManager( + absl::make_unique(), true), + IsOk()); + util::StatusOr> handle = + KeysetHandle::GenerateNew(key_template, KeyGenConfigGlobalRegistry()); + ASSERT_THAT(handle, IsOk()); + + // Fails to parse this key type, so falls back to legacy proto key. + EXPECT_THAT(dynamic_cast( + (*handle)->GetPrimary().GetKey().get()), + NotNull()); + + util::StatusOr parameters = + PrfBasedKeyDerivationParameters::Builder() + .SetPrfParameters(GetAesCmacPrfParameters()) + .SetDerivedKeyParameters(GetXChaCha20Poly1305Parameters()) + .Build(); + ASSERT_THAT(parameters, IsOk()); + util::StatusOr key = + PrfBasedKeyDerivationKey::Create(*parameters, GetAesCmacPrfKey(), + /*id_requirement=*/123, + GetPartialKeyAccess()); + ASSERT_THAT(key, IsOk()); + + // Fails to serialize this key type. + EXPECT_THAT(KeysetHandleBuilder() + .AddEntry(KeysetHandleBuilder::Entry::CreateFromCopyableKey( + *key, KeyStatus::kEnabled, /*is_primary=*/true)) + .Build() + .status(), + StatusIs(absl::StatusCode::kInvalidArgument, + HasSubstr("Failed to serialize"))); + + ASSERT_THAT(KeyDerivationConfig::Register(), IsOk()); + + util::StatusOr> handle2 = + KeysetHandle::GenerateNew(key_template, KeyGenConfigGlobalRegistry()); + ASSERT_THAT(handle2, IsOk()); + + EXPECT_THAT(dynamic_cast( + (*handle2)->GetPrimary().GetKey().get()), + NotNull()); + + EXPECT_THAT(KeysetHandleBuilder() + .AddEntry(KeysetHandleBuilder::Entry::CreateFromCopyableKey( + *key, KeyStatus::kEnabled, /*is_primary=*/true)) + .Build(), + IsOk()); +} + } // namespace +} // namespace internal } // namespace tink } // namespace crypto