From 6ab470572ee0afbad3ac8b438c1a5d535b691459 Mon Sep 17 00:00:00 2001 From: Ioana Nedelcu Date: Fri, 27 Oct 2023 09:23:38 -0700 Subject: [PATCH] Add RsaSsaPkcs1 proto parser and serializer for the parameters objects. PiperOrigin-RevId: 577220674 Change-Id: I77558b6de4b917299d58177bbf4426103ad05509 --- tink/signature/BUILD.bazel | 46 +++ tink/signature/CMakeLists.txt | 45 +++ .../rsa_ssa_pkcs1_proto_serialization.cc | 210 ++++++++++++ .../rsa_ssa_pkcs1_proto_serialization.h | 31 ++ .../rsa_ssa_pkcs1_proto_serialization_test.cc | 298 ++++++++++++++++++ 5 files changed, 630 insertions(+) create mode 100644 tink/signature/rsa_ssa_pkcs1_proto_serialization.cc create mode 100644 tink/signature/rsa_ssa_pkcs1_proto_serialization.h create mode 100644 tink/signature/rsa_ssa_pkcs1_proto_serialization_test.cc diff --git a/tink/signature/BUILD.bazel b/tink/signature/BUILD.bazel index 08c682c1..e39f6c34 100644 --- a/tink/signature/BUILD.bazel +++ b/tink/signature/BUILD.bazel @@ -600,6 +600,29 @@ cc_library( ], ) +cc_library( + name = "rsa_ssa_pkcs1_proto_serialization", + srcs = ["rsa_ssa_pkcs1_proto_serialization.cc"], + hdrs = ["rsa_ssa_pkcs1_proto_serialization.h"], + include_prefix = "tink/signature", + deps = [ + ":rsa_ssa_pkcs1_parameters", + "//tink:big_integer", + "//tink/internal:mutable_serialization_registry", + "//tink/internal:parameters_parser", + "//tink/internal:parameters_serializer", + "//tink/internal:proto_parameters_serialization", + "//proto:common_cc_proto", + "//proto:rsa_ssa_pkcs1_cc_proto", + "//proto:tink_cc_proto", + "//tink/util:status", + "//tink/util:statusor", + "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/status", + "@com_google_absl//absl/strings:string_view", + ], +) + # tests cc_test( @@ -1115,3 +1138,26 @@ cc_test( "@com_google_googletest//:gtest_main", ], ) + +cc_test( + name = "rsa_ssa_pkcs1_proto_serialization_test", + srcs = ["rsa_ssa_pkcs1_proto_serialization_test.cc"], + deps = [ + ":rsa_ssa_pkcs1_parameters", + ":rsa_ssa_pkcs1_proto_serialization", + "//tink:big_integer", + "//tink:parameters", + "//tink/internal:mutable_serialization_registry", + "//tink/internal:proto_parameters_serialization", + "//tink/internal:serialization", + "//proto:common_cc_proto", + "//proto:rsa_ssa_pkcs1_cc_proto", + "//proto:tink_cc_proto", + "//tink/util:statusor", + "//tink/util:test_matchers", + "@com_google_absl//absl/status", + "@com_google_absl//absl/strings:string_view", + "@com_google_absl//absl/types:optional", + "@com_google_googletest//:gtest_main", + ], +) diff --git a/tink/signature/CMakeLists.txt b/tink/signature/CMakeLists.txt index d50e5c35..9a23b7e3 100644 --- a/tink/signature/CMakeLists.txt +++ b/tink/signature/CMakeLists.txt @@ -571,6 +571,28 @@ tink_cc_library( tink::signature::internal::key_gen_config_v0 ) +tink_cc_library( + NAME rsa_ssa_pkcs1_proto_serialization + SRCS + rsa_ssa_pkcs1_proto_serialization.cc + rsa_ssa_pkcs1_proto_serialization.h + DEPS + tink::signature::rsa_ssa_pkcs1_parameters + absl::core_headers + absl::status + absl::string_view + tink::core::big_integer + tink::internal::mutable_serialization_registry + tink::internal::parameters_parser + tink::internal::parameters_serializer + tink::internal::proto_parameters_serialization + tink::util::status + tink::util::statusor + tink::proto::common_cc_proto + tink::proto::rsa_ssa_pkcs1_cc_proto + tink::proto::tink_cc_proto +) + # tests tink_cc_test( @@ -1070,3 +1092,26 @@ tink_cc_test( tink::util::test_matchers tink::proto::tink_cc_proto ) + +tink_cc_test( + NAME rsa_ssa_pkcs1_proto_serialization_test + SRCS + rsa_ssa_pkcs1_proto_serialization_test.cc + DEPS + tink::signature::rsa_ssa_pkcs1_parameters + tink::signature::rsa_ssa_pkcs1_proto_serialization + gmock + absl::status + absl::string_view + absl::optional + tink::core::big_integer + tink::core::parameters + tink::internal::mutable_serialization_registry + tink::internal::proto_parameters_serialization + tink::internal::serialization + tink::util::statusor + tink::util::test_matchers + tink::proto::common_cc_proto + tink::proto::rsa_ssa_pkcs1_cc_proto + tink::proto::tink_cc_proto +) diff --git a/tink/signature/rsa_ssa_pkcs1_proto_serialization.cc b/tink/signature/rsa_ssa_pkcs1_proto_serialization.cc new file mode 100644 index 00000000..1f4c4c4d --- /dev/null +++ b/tink/signature/rsa_ssa_pkcs1_proto_serialization.cc @@ -0,0 +1,210 @@ +// Copyright 2023 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/signature/rsa_ssa_pkcs1_proto_serialization.h" +#include + +#include "absl/base/attributes.h" +#include "absl/status/status.h" +#include "absl/strings/string_view.h" +#include "tink/big_integer.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/signature/rsa_ssa_pkcs1_parameters.h" +#include "tink/util/status.h" +#include "tink/util/statusor.h" +#include "proto/common.pb.h" +#include "proto/rsa_ssa_pkcs1.pb.h" +#include "proto/tink.pb.h" + +namespace crypto { +namespace tink { +namespace { + +using ::google::crypto::tink::HashType; +using ::google::crypto::tink::OutputPrefixType; +using ::google::crypto::tink::RsaSsaPkcs1KeyFormat; +using ::google::crypto::tink::RsaSsaPkcs1Params; + +using RsaSsaPkcs1ProtoParametersParserImpl = + internal::ParametersParserImpl; +using RsaSsaPkcs1ProtoParametersSerializerImpl = + internal::ParametersSerializerImpl; + +const absl::string_view kPrivateTypeUrl = + "type.googleapis.com/google.crypto.tink.RsaSsaPkcs1PrivateKey"; + +util::StatusOr ToVariant( + OutputPrefixType output_prefix_type) { + switch (output_prefix_type) { + case OutputPrefixType::LEGACY: + ABSL_FALLTHROUGH_INTENDED; // Parse LEGACY output prefix as CRUNCHY. + case OutputPrefixType::CRUNCHY: + return RsaSsaPkcs1Parameters::Variant::kCrunchy; + case OutputPrefixType::RAW: + return RsaSsaPkcs1Parameters::Variant::kNoPrefix; + case OutputPrefixType::TINK: + return RsaSsaPkcs1Parameters::Variant::kTink; + default: + return util::Status(absl::StatusCode::kInvalidArgument, + "Could not determine RsaSsaPkcs1Parameters::Variant"); + } +} + +util::StatusOr ToOutputPrefixType( + RsaSsaPkcs1Parameters::Variant variant) { + switch (variant) { + case RsaSsaPkcs1Parameters::Variant::kCrunchy: + return OutputPrefixType::CRUNCHY; + case RsaSsaPkcs1Parameters::Variant::kNoPrefix: + return OutputPrefixType::RAW; + case RsaSsaPkcs1Parameters::Variant::kTink: + return OutputPrefixType::TINK; + default: + return util::Status(absl::StatusCode::kInvalidArgument, + "Could not determine output prefix type."); + } +} + +util::StatusOr ToEnumHashType( + HashType hash_type) { + switch (hash_type) { + case HashType::SHA256: + return RsaSsaPkcs1Parameters::HashType::kSha256; + case HashType::SHA384: + return RsaSsaPkcs1Parameters::HashType::kSha384; + case HashType::SHA512: + return RsaSsaPkcs1Parameters::HashType::kSha512; + default: + return util::Status(absl::StatusCode::kInvalidArgument, + "Could not determine HashType"); + } +} + +util::StatusOr ToProtoHashType( + RsaSsaPkcs1Parameters::HashType hash_type) { + switch (hash_type) { + case RsaSsaPkcs1Parameters::HashType::kSha256: + return HashType::SHA256; + case RsaSsaPkcs1Parameters::HashType::kSha384: + return HashType::SHA384; + case RsaSsaPkcs1Parameters::HashType::kSha512: + return HashType::SHA512; + default: + return util::Status( + absl::StatusCode::kInvalidArgument, + "Could not determine RsaSsaPkcs1Parameters::HashType"); + } +} + +util::StatusOr ParseParameters( + const internal::ProtoParametersSerialization& serialization) { + if (serialization.GetKeyTemplate().type_url() != kPrivateTypeUrl) { + return util::Status(absl::StatusCode::kInvalidArgument, + "Wrong type URL when parsing RsaSsaPkcs1Parameters."); + } + + RsaSsaPkcs1KeyFormat proto_key_format; + if (!proto_key_format.ParseFromString( + serialization.GetKeyTemplate().value())) { + return util::Status(absl::StatusCode::kInvalidArgument, + "Failed to parse RsaSsaPkcs1KeyFormat proto"); + } + if (!proto_key_format.has_params()) { + return util::Status(absl::StatusCode::kInvalidArgument, + "RsaSsaPkcs1KeyFormat proto is missing params field."); + } + + util::StatusOr variant = + ToVariant(serialization.GetKeyTemplate().output_prefix_type()); + if (!variant.ok()) { + return variant.status(); + } + + util::StatusOr hash_type = + ToEnumHashType(proto_key_format.params().hash_type()); + if (!hash_type.ok()) { + return hash_type.status(); + } + + return RsaSsaPkcs1Parameters::Builder() + .SetVariant(*variant) + .SetHashType(*hash_type) + .SetModulusSizeInBits(proto_key_format.modulus_size_in_bits()) + .SetPublicExponent(BigInteger(proto_key_format.public_exponent())) + .Build(); +} + +util::StatusOr SerializeParameters( + const RsaSsaPkcs1Parameters& parameters) { + util::StatusOr output_prefix_type = + ToOutputPrefixType(parameters.GetVariant()); + if (!output_prefix_type.ok()) { + return output_prefix_type.status(); + } + + util::StatusOr hash_type = + ToProtoHashType(parameters.GetHashType()); + if (!hash_type.ok()) { + return hash_type.status(); + } + + RsaSsaPkcs1Params params; + params.set_hash_type(*hash_type); + RsaSsaPkcs1KeyFormat proto_key_format; + proto_key_format.set_modulus_size_in_bits(parameters.GetModulusSizeInBits()); + proto_key_format.set_public_exponent( + std::string(parameters.GetPublicExponent().GetValue())); + *proto_key_format.mutable_params() = params; + + return internal::ProtoParametersSerialization::Create( + kPrivateTypeUrl, *output_prefix_type, + proto_key_format.SerializeAsString()); +} + +RsaSsaPkcs1ProtoParametersParserImpl* RsaSsaPkcs1ProtoParametersParser() { + static auto* parser = new RsaSsaPkcs1ProtoParametersParserImpl( + kPrivateTypeUrl, ParseParameters); + return parser; +} + +RsaSsaPkcs1ProtoParametersSerializerImpl* +RsaSsaPkcs1ProtoParametersSerializer() { + static auto* serializer = new RsaSsaPkcs1ProtoParametersSerializerImpl( + kPrivateTypeUrl, SerializeParameters); + return serializer; +} + +} // namespace + +util::Status RegisterRsaSsaPkcs1ProtoSerialization() { + util::Status status = + internal::MutableSerializationRegistry::GlobalInstance() + .RegisterParametersParser(RsaSsaPkcs1ProtoParametersParser()); + if (!status.ok()) { + return status; + } + + return internal::MutableSerializationRegistry::GlobalInstance() + .RegisterParametersSerializer(RsaSsaPkcs1ProtoParametersSerializer()); +} + +} // namespace tink +} // namespace crypto diff --git a/tink/signature/rsa_ssa_pkcs1_proto_serialization.h b/tink/signature/rsa_ssa_pkcs1_proto_serialization.h new file mode 100644 index 00000000..cd0fe7c2 --- /dev/null +++ b/tink/signature/rsa_ssa_pkcs1_proto_serialization.h @@ -0,0 +1,31 @@ +// Copyright 2023 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_SIGNATURE_RSA_SSA_PKCS1_PROTO_SERIALIZATION_H_ +#define TINK_SIGNATURE_RSA_SSA_PKCS1_PROTO_SERIALIZATION_H_ + +#include "tink/util/status.h" + +namespace crypto { +namespace tink { + +// Registers proto parsers and serializers for RsaSsaPkcs1 parameters and keys. +crypto::tink::util::Status RegisterRsaSsaPkcs1ProtoSerialization(); + +} // namespace tink +} // namespace crypto + +#endif // TINK_SIGNATURE_RSA_SSA_PKCS1_PROTO_SERIALIZATION_H_ diff --git a/tink/signature/rsa_ssa_pkcs1_proto_serialization_test.cc b/tink/signature/rsa_ssa_pkcs1_proto_serialization_test.cc new file mode 100644 index 00000000..c5f84fd1 --- /dev/null +++ b/tink/signature/rsa_ssa_pkcs1_proto_serialization_test.cc @@ -0,0 +1,298 @@ +// Copyright 2023 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/signature/rsa_ssa_pkcs1_proto_serialization.h" + +#include +#include + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "absl/status/status.h" +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "tink/big_integer.h" +#include "tink/internal/mutable_serialization_registry.h" +#include "tink/internal/proto_parameters_serialization.h" +#include "tink/internal/serialization.h" +#include "tink/parameters.h" +#include "tink/signature/rsa_ssa_pkcs1_parameters.h" +#include "tink/util/statusor.h" +#include "tink/util/test_matchers.h" +#include "proto/common.pb.h" +#include "proto/rsa_ssa_pkcs1.pb.h" +#include "proto/tink.pb.h" + +namespace crypto { +namespace tink { +namespace { + +using ::crypto::tink::test::IsOk; +using ::crypto::tink::test::StatusIs; +using ::google::crypto::tink::HashType; +using ::google::crypto::tink::OutputPrefixType; +using ::google::crypto::tink::RsaSsaPkcs1KeyFormat; +using ::testing::Eq; +using ::testing::IsTrue; +using ::testing::NotNull; +using ::testing::TestWithParam; +using ::testing::Values; + +struct TestCase { + RsaSsaPkcs1Parameters::Variant variant; + OutputPrefixType output_prefix_type; + RsaSsaPkcs1Parameters::HashType hash_type; + HashType proto_hash_type; + int modulus_size_in_bits; + absl::optional id; + std::string output_prefix; +}; + +const std::string& kF4Str = *new std::string("\x1\0\x1", 3); // 65537 + +const absl::string_view kPrivateTypeUrl = + "type.googleapis.com/google.crypto.tink.RsaSsaPkcs1PrivateKey"; + +class RsaSsaPkcs1ProtoSerializationTest : public TestWithParam { + protected: + void SetUp() override { + internal::MutableSerializationRegistry::GlobalInstance().Reset(); + } +}; + +TEST_F(RsaSsaPkcs1ProtoSerializationTest, RegisterTwiceSucceeds) { + ASSERT_THAT(RegisterRsaSsaPkcs1ProtoSerialization(), IsOk()); + ASSERT_THAT(RegisterRsaSsaPkcs1ProtoSerialization(), IsOk()); +} + +INSTANTIATE_TEST_SUITE_P( + RsaSsaPkcs1ProtoSerializationTestSuite, RsaSsaPkcs1ProtoSerializationTest, + Values(TestCase{RsaSsaPkcs1Parameters::Variant::kTink, + OutputPrefixType::TINK, + RsaSsaPkcs1Parameters::HashType::kSha256, HashType::SHA256, + /*modulus_size=*/2048, /*id=*/0x02030400, + /*output_prefix=*/std::string("\x01\x02\x03\x04\x00", 5)}, + TestCase{RsaSsaPkcs1Parameters::Variant::kCrunchy, + OutputPrefixType::CRUNCHY, + RsaSsaPkcs1Parameters::HashType::kSha256, HashType::SHA256, + /*modulus_size=*/2048, /*id=*/0x01030005, + /*output_prefix=*/std::string("\x00\x01\x03\x00\x05", 5)}, + TestCase{RsaSsaPkcs1Parameters::Variant::kCrunchy, + OutputPrefixType::CRUNCHY, + RsaSsaPkcs1Parameters::HashType::kSha384, HashType::SHA384, + /*modulus_size=*/3072, /*id=*/0x07080910, + /*output_prefix=*/std::string("\x00\x07\x08\x09\x10", 5)}, + TestCase{RsaSsaPkcs1Parameters::Variant::kNoPrefix, + OutputPrefixType::RAW, + RsaSsaPkcs1Parameters::HashType::kSha512, HashType::SHA512, + /*modulus_size=*/3072, /*id=*/absl::nullopt, + /*output_prefix=*/""})); + +TEST_P(RsaSsaPkcs1ProtoSerializationTest, ParseParametersSucceeds) { + TestCase test_case = GetParam(); + ASSERT_THAT(RegisterRsaSsaPkcs1ProtoSerialization(), IsOk()); + + RsaSsaPkcs1KeyFormat key_format_proto; + key_format_proto.set_modulus_size_in_bits(test_case.modulus_size_in_bits); + key_format_proto.set_public_exponent(kF4Str); + key_format_proto.mutable_params()->set_hash_type(test_case.proto_hash_type); + + util::StatusOr serialization = + internal::ProtoParametersSerialization::Create( + kPrivateTypeUrl, test_case.output_prefix_type, + key_format_proto.SerializeAsString()); + ASSERT_THAT(serialization, IsOk()); + + util::StatusOr> parameters = + internal::MutableSerializationRegistry::GlobalInstance().ParseParameters( + *serialization); + ASSERT_THAT(parameters, IsOk()); + + EXPECT_THAT((*parameters)->HasIdRequirement(), test_case.id.has_value()); + const RsaSsaPkcs1Parameters* rsa_ssa_pkcs1_parameters = + dynamic_cast(parameters->get()); + ASSERT_THAT(rsa_ssa_pkcs1_parameters, NotNull()); + EXPECT_THAT(rsa_ssa_pkcs1_parameters->GetVariant(), Eq(test_case.variant)); + EXPECT_THAT(rsa_ssa_pkcs1_parameters->GetModulusSizeInBits(), + Eq(test_case.modulus_size_in_bits)); + EXPECT_THAT(rsa_ssa_pkcs1_parameters->GetHashType(), Eq(test_case.hash_type)); + EXPECT_THAT(rsa_ssa_pkcs1_parameters->GetPublicExponent(), + Eq(BigInteger(kF4Str))); +} + +TEST_F(RsaSsaPkcs1ProtoSerializationTest, ParseParametersLegacyAsCrunchy) { + ASSERT_THAT(RegisterRsaSsaPkcs1ProtoSerialization(), IsOk()); + + RsaSsaPkcs1KeyFormat key_format_proto; + key_format_proto.set_modulus_size_in_bits(2048); + key_format_proto.set_public_exponent(kF4Str); + key_format_proto.mutable_params()->set_hash_type(HashType::SHA256); + + util::StatusOr serialization = + internal::ProtoParametersSerialization::Create( + kPrivateTypeUrl, OutputPrefixType::LEGACY, + key_format_proto.SerializeAsString()); + ASSERT_THAT(serialization, IsOk()); + + util::StatusOr> parameters = + internal::MutableSerializationRegistry::GlobalInstance().ParseParameters( + *serialization); + ASSERT_THAT(parameters, IsOk()); + + EXPECT_THAT((*parameters)->HasIdRequirement(), IsTrue()); + + const RsaSsaPkcs1Parameters* rsa_ssa_pkcs1_parameters = + dynamic_cast(parameters->get()); + + ASSERT_THAT(rsa_ssa_pkcs1_parameters, NotNull()); + EXPECT_THAT(rsa_ssa_pkcs1_parameters->GetVariant(), + Eq(RsaSsaPkcs1Parameters::Variant::kCrunchy)); + EXPECT_THAT(rsa_ssa_pkcs1_parameters->GetModulusSizeInBits(), Eq(2048)); + EXPECT_THAT(rsa_ssa_pkcs1_parameters->GetHashType(), + Eq(RsaSsaPkcs1Parameters::HashType::kSha256)); + EXPECT_THAT(rsa_ssa_pkcs1_parameters->GetPublicExponent(), + Eq(BigInteger(kF4Str))); +} + +TEST_F(RsaSsaPkcs1ProtoSerializationTest, + ParseParametersWithInvalidSerializationFails) { + ASSERT_THAT(RegisterRsaSsaPkcs1ProtoSerialization(), IsOk()); + + util::StatusOr serialization = + internal::ProtoParametersSerialization::Create( + kPrivateTypeUrl, OutputPrefixType::RAW, "invalid_serialization"); + ASSERT_THAT(serialization, IsOk()); + + util::StatusOr> parameters = + internal::MutableSerializationRegistry::GlobalInstance().ParseParameters( + *serialization); + + ASSERT_THAT(parameters.status(), + StatusIs(absl::StatusCode::kInvalidArgument)); +} + +TEST_F(RsaSsaPkcs1ProtoSerializationTest, + ParseParametersKeyFormatWithoutParamsFails) { + ASSERT_THAT(RegisterRsaSsaPkcs1ProtoSerialization(), IsOk()); + + RsaSsaPkcs1KeyFormat key_format_proto; + key_format_proto.set_modulus_size_in_bits(2048); + key_format_proto.set_public_exponent(kF4Str); + + util::StatusOr serialization = + internal::ProtoParametersSerialization::Create( + kPrivateTypeUrl, OutputPrefixType::RAW, + key_format_proto.SerializeAsString()); + ASSERT_THAT(serialization, IsOk()); + + util::StatusOr> parameters = + internal::MutableSerializationRegistry::GlobalInstance().ParseParameters( + *serialization); + + ASSERT_THAT(parameters.status(), + StatusIs(absl::StatusCode::kInvalidArgument)); +} + +TEST_F(RsaSsaPkcs1ProtoSerializationTest, + ParseParametersWithUnkownOutputPrefixFails) { + ASSERT_THAT(RegisterRsaSsaPkcs1ProtoSerialization(), IsOk()); + + RsaSsaPkcs1KeyFormat key_format_proto; + key_format_proto.set_modulus_size_in_bits(2048); + key_format_proto.set_public_exponent(kF4Str); + key_format_proto.mutable_params()->set_hash_type(HashType::SHA256); + + util::StatusOr serialization = + internal::ProtoParametersSerialization::Create( + kPrivateTypeUrl, OutputPrefixType::UNKNOWN_PREFIX, + key_format_proto.SerializeAsString()); + ASSERT_THAT(serialization, IsOk()); + + util::StatusOr> parameters = + internal::MutableSerializationRegistry::GlobalInstance().ParseParameters( + *serialization); + + ASSERT_THAT(parameters.status(), + StatusIs(absl::StatusCode::kInvalidArgument)); +} + +TEST_F(RsaSsaPkcs1ProtoSerializationTest, ParseParametersWithUnkownHashFails) { + ASSERT_THAT(RegisterRsaSsaPkcs1ProtoSerialization(), IsOk()); + + RsaSsaPkcs1KeyFormat key_format_proto; + key_format_proto.set_modulus_size_in_bits(2048); + key_format_proto.set_public_exponent(kF4Str); + key_format_proto.mutable_params()->set_hash_type(HashType::UNKNOWN_HASH); + + util::StatusOr serialization = + internal::ProtoParametersSerialization::Create( + kPrivateTypeUrl, OutputPrefixType::TINK, + key_format_proto.SerializeAsString()); + ASSERT_THAT(serialization, IsOk()); + + util::StatusOr> parameters = + internal::MutableSerializationRegistry::GlobalInstance().ParseParameters( + *serialization); + + ASSERT_THAT(parameters.status(), + StatusIs(absl::StatusCode::kInvalidArgument)); +} + +TEST_P(RsaSsaPkcs1ProtoSerializationTest, SerializeParametersSucceeds) { + TestCase test_case = GetParam(); + ASSERT_THAT(RegisterRsaSsaPkcs1ProtoSerialization(), IsOk()); + + util::StatusOr parameters = + RsaSsaPkcs1Parameters::Builder() + .SetVariant(test_case.variant) + .SetHashType(test_case.hash_type) + .SetModulusSizeInBits(test_case.modulus_size_in_bits) + .SetPublicExponent(BigInteger(kF4Str)) + .Build(); + ASSERT_THAT(parameters, IsOk()); + + util::StatusOr> serialization = + internal::MutableSerializationRegistry::GlobalInstance() + .SerializeParameters( + *parameters); + ASSERT_THAT(serialization, IsOk()); + + EXPECT_THAT((*serialization)->ObjectIdentifier(), Eq(kPrivateTypeUrl)); + + const internal::ProtoParametersSerialization* proto_serialization = + dynamic_cast( + serialization->get()); + + ASSERT_THAT(proto_serialization, NotNull()); + EXPECT_THAT(proto_serialization->GetKeyTemplate().type_url(), + Eq(kPrivateTypeUrl)); + EXPECT_THAT(proto_serialization->GetKeyTemplate().output_prefix_type(), + Eq(test_case.output_prefix_type)); + + RsaSsaPkcs1KeyFormat key_format; + ASSERT_THAT( + key_format.ParseFromString(proto_serialization->GetKeyTemplate().value()), + IsTrue()); + + ASSERT_THAT(key_format.has_params(), IsTrue()); + EXPECT_THAT(key_format.params().hash_type(), Eq(test_case.proto_hash_type)); + EXPECT_THAT(key_format.modulus_size_in_bits(), + Eq(test_case.modulus_size_in_bits)); + EXPECT_THAT(key_format.public_exponent(), Eq(kF4Str)); +} + +} // namespace +} // namespace tink +} // namespace crypto