diff options
author | wconner <wconner@google.com> | 2023-08-04 04:31:00 -0700 |
---|---|---|
committer | Copybara-Service <copybara-worker@google.com> | 2023-08-04 04:32:38 -0700 |
commit | 4fa7e0322848bcf34eb200510da0619ae0b3636b (patch) | |
tree | f7f89649378d7f0ab53d098a44c2d370427a2ec5 | |
parent | 89464905f119362ea232f2e094cccb5eb80150bc (diff) | |
download | tink-4fa7e0322848bcf34eb200510da0619ae0b3636b.tar.gz |
Add Ed25519 public key proto parsers and serializers.
PiperOrigin-RevId: 553766329
-rw-r--r-- | cc/signature/BUILD.bazel | 16 | ||||
-rw-r--r-- | cc/signature/CMakeLists.txt | 16 | ||||
-rw-r--r-- | cc/signature/ed25519_proto_serialization.cc | 107 | ||||
-rw-r--r-- | cc/signature/ed25519_proto_serialization_test.cc | 151 |
4 files changed, 269 insertions, 21 deletions
diff --git a/cc/signature/BUILD.bazel b/cc/signature/BUILD.bazel index b5a549e31..6d16ccf28 100644 --- a/cc/signature/BUILD.bazel +++ b/cc/signature/BUILD.bazel @@ -486,9 +486,17 @@ cc_library( include_prefix = "tink/signature", deps = [ ":ed25519_parameters", + ":ed25519_public_key", + "//:insecure_secret_key_access", + "//:partial_key_access", + "//:restricted_data", + "//:secret_key_access_token", + "//internal:key_parser", + "//internal:key_serializer", "//internal:mutable_serialization_registry", "//internal:parameters_parser", "//internal:parameters_serializer", + "//internal:proto_key_serialization", "//internal:proto_parameters_serialization", "//proto:ed25519_cc_proto", "//proto:tink_cc_proto", @@ -496,6 +504,7 @@ cc_library( "//util:statusor", "@com_google_absl//absl/status", "@com_google_absl//absl/strings", + "@com_google_absl//absl/types:optional", ], ) @@ -917,12 +926,19 @@ cc_test( deps = [ ":ed25519_parameters", ":ed25519_proto_serialization", + ":ed25519_public_key", + "//:insecure_secret_key_access", + "//:key", "//:parameters", + "//:partial_key_access", + "//:restricted_data", "//internal:mutable_serialization_registry", + "//internal:proto_key_serialization", "//internal:proto_parameters_serialization", "//internal:serialization", "//proto:ed25519_cc_proto", "//proto:tink_cc_proto", + "//subtle:random", "//util:statusor", "//util:test_matchers", "@com_google_absl//absl/status", diff --git a/cc/signature/CMakeLists.txt b/cc/signature/CMakeLists.txt index 778fd63e4..686ad21a9 100644 --- a/cc/signature/CMakeLists.txt +++ b/cc/signature/CMakeLists.txt @@ -463,11 +463,20 @@ tink_cc_library( ed25519_proto_serialization.h DEPS tink::signature::ed25519_parameters + tink::signature::ed25519_public_key absl::status absl::strings + absl::optional + tink::core::insecure_secret_key_access + tink::core::partial_key_access + tink::core::restricted_data + tink::core::secret_key_access_token + tink::internal::key_parser + tink::internal::key_serializer tink::internal::mutable_serialization_registry tink::internal::parameters_parser tink::internal::parameters_serializer + tink::internal::proto_key_serialization tink::internal::proto_parameters_serialization tink::util::status tink::util::statusor @@ -878,13 +887,20 @@ tink_cc_test( DEPS tink::signature::ed25519_parameters tink::signature::ed25519_proto_serialization + tink::signature::ed25519_public_key gmock absl::status absl::optional + tink::core::insecure_secret_key_access + tink::core::key tink::core::parameters + tink::core::partial_key_access + tink::core::restricted_data tink::internal::mutable_serialization_registry + tink::internal::proto_key_serialization tink::internal::proto_parameters_serialization tink::internal::serialization + tink::subtle::random tink::util::statusor tink::util::test_matchers tink::proto::ed25519_cc_proto diff --git a/cc/signature/ed25519_proto_serialization.cc b/cc/signature/ed25519_proto_serialization.cc index fc022c0cb..df5103cce 100644 --- a/cc/signature/ed25519_proto_serialization.cc +++ b/cc/signature/ed25519_proto_serialization.cc @@ -16,13 +16,24 @@ #include "tink/signature/ed25519_proto_serialization.h" +#include <string> + #include "absl/status/status.h" #include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "tink/insecure_secret_key_access.h" +#include "tink/internal/key_parser.h" +#include "tink/internal/key_serializer.h" #include "tink/internal/mutable_serialization_registry.h" #include "tink/internal/parameters_parser.h" #include "tink/internal/parameters_serializer.h" +#include "tink/internal/proto_key_serialization.h" #include "tink/internal/proto_parameters_serialization.h" +#include "tink/partial_key_access.h" +#include "tink/restricted_data.h" +#include "tink/secret_key_access_token.h" #include "tink/signature/ed25519_parameters.h" +#include "tink/signature/ed25519_public_key.h" #include "tink/util/status.h" #include "tink/util/statusor.h" #include "proto/ed25519.pb.h" @@ -41,7 +52,14 @@ using Ed25519ProtoParametersParserImpl = using Ed25519ProtoParametersSerializerImpl = internal::ParametersSerializerImpl<Ed25519Parameters, internal::ProtoParametersSerialization>; - +using Ed25519ProtoPublicKeyParserImpl = + internal::KeyParserImpl<internal::ProtoKeySerialization, Ed25519PublicKey>; +using Ed25519ProtoPublicKeySerializerImpl = + internal::KeySerializerImpl<Ed25519PublicKey, + internal::ProtoKeySerialization>; + +const absl::string_view kPublicTypeUrl = + "type.googleapis.com/google.crypto.tink.Ed25519PublicKey"; const absl::string_view kPrivateTypeUrl = "type.googleapis.com/google.crypto.tink.Ed25519PrivateKey"; @@ -106,6 +124,44 @@ util::StatusOr<Ed25519Parameters> ParseParameters( return Ed25519Parameters::Create(*variant); } +util::StatusOr<Ed25519PublicKey> ParsePublicKey( + const internal::ProtoKeySerialization& serialization, + absl::optional<SecretKeyAccessToken> token) { + if (serialization.TypeUrl() != kPublicTypeUrl) { + return util::Status(absl::StatusCode::kInvalidArgument, + "Wrong type URL when parsing Ed25519PublicKey."); + } + + google::crypto::tink::Ed25519PublicKey proto_key; + RestrictedData restricted_data = serialization.SerializedKeyProto(); + // OSS proto library complains if input is not converted to a string. + if (!proto_key.ParseFromString(std::string( + restricted_data.GetSecret(InsecureSecretKeyAccess::Get())))) { + return util::Status(absl::StatusCode::kInvalidArgument, + "Failed to parse Ed25519PublicKey proto"); + } + if (proto_key.version() != 0) { + return util::Status(absl::StatusCode::kInvalidArgument, + "Only version 0 keys are accepted."); + } + + util::StatusOr<Ed25519Parameters::Variant> variant = + ToVariant(serialization.GetOutputPrefixType()); + if (!variant.ok()) { + return variant.status(); + } + + util::StatusOr<Ed25519Parameters> parameters = + Ed25519Parameters::Create(*variant); + if (!parameters.ok()) { + return parameters.status(); + } + + return Ed25519PublicKey::Create(*parameters, proto_key.key_value(), + serialization.IdRequirement(), + GetPartialKeyAccess()); +} + util::StatusOr<internal::ProtoParametersSerialization> SerializeParameters( const Ed25519Parameters& parameters) { util::StatusOr<OutputPrefixType> output_prefix_type = @@ -122,6 +178,28 @@ util::StatusOr<internal::ProtoParametersSerialization> SerializeParameters( proto_key_format.SerializeAsString()); } +util::StatusOr<internal::ProtoKeySerialization> SerializePublicKey( + const Ed25519PublicKey& key, absl::optional<SecretKeyAccessToken> token) { + google::crypto::tink::Ed25519PublicKey proto_key; + proto_key.set_version(0); + // OSS proto library complains if input is not converted to a string. + proto_key.set_key_value( + std::string(key.GetPublicKeyBytes(GetPartialKeyAccess()))); + + util::StatusOr<OutputPrefixType> output_prefix_type = + ToOutputPrefixType(key.GetParameters().GetVariant()); + if (!output_prefix_type.ok()) { + return output_prefix_type.status(); + } + + RestrictedData restricted_output = RestrictedData( + proto_key.SerializeAsString(), InsecureSecretKeyAccess::Get()); + return internal::ProtoKeySerialization::Create( + kPublicTypeUrl, restricted_output, + google::crypto::tink::KeyData::ASYMMETRIC_PUBLIC, *output_prefix_type, + key.GetIdRequirement()); +} + Ed25519ProtoParametersParserImpl* Ed25519ProtoParametersParser() { static auto* parser = new Ed25519ProtoParametersParserImpl(kPrivateTypeUrl, ParseParameters); @@ -134,6 +212,18 @@ Ed25519ProtoParametersSerializerImpl* Ed25519ProtoParametersSerializer() { return serializer; } +Ed25519ProtoPublicKeyParserImpl* Ed25519ProtoPublicKeyParser() { + static auto* parser = + new Ed25519ProtoPublicKeyParserImpl(kPublicTypeUrl, ParsePublicKey); + return parser; +} + +Ed25519ProtoPublicKeySerializerImpl* Ed25519ProtoPublicKeySerializer() { + static auto* serializer = + new Ed25519ProtoPublicKeySerializerImpl(SerializePublicKey); + return serializer; +} + } // namespace util::Status RegisterEd25519ProtoSerialization() { @@ -144,8 +234,21 @@ util::Status RegisterEd25519ProtoSerialization() { return status; } + status = + internal::MutableSerializationRegistry::GlobalInstance() + .RegisterParametersSerializer(Ed25519ProtoParametersSerializer()); + if (!status.ok()) { + return status; + } + + status = internal::MutableSerializationRegistry::GlobalInstance() + .RegisterKeyParser(Ed25519ProtoPublicKeyParser()); + if (!status.ok()) { + return status; + } + return internal::MutableSerializationRegistry::GlobalInstance() - .RegisterParametersSerializer(Ed25519ProtoParametersSerializer()); + .RegisterKeySerializer(Ed25519ProtoPublicKeySerializer()); } } // namespace tink diff --git a/cc/signature/ed25519_proto_serialization_test.cc b/cc/signature/ed25519_proto_serialization_test.cc index a2730c57d..04a839ed2 100644 --- a/cc/signature/ed25519_proto_serialization_test.cc +++ b/cc/signature/ed25519_proto_serialization_test.cc @@ -23,11 +23,18 @@ #include "gtest/gtest.h" #include "absl/status/status.h" #include "absl/types/optional.h" +#include "tink/insecure_secret_key_access.h" #include "tink/internal/mutable_serialization_registry.h" +#include "tink/internal/proto_key_serialization.h" #include "tink/internal/proto_parameters_serialization.h" #include "tink/internal/serialization.h" +#include "tink/key.h" #include "tink/parameters.h" +#include "tink/partial_key_access.h" +#include "tink/restricted_data.h" #include "tink/signature/ed25519_parameters.h" +#include "tink/signature/ed25519_public_key.h" +#include "tink/subtle/random.h" #include "tink/util/statusor.h" #include "tink/util/test_matchers.h" #include "proto/ed25519.pb.h" @@ -37,13 +44,16 @@ namespace crypto { namespace tink { namespace { +using ::crypto::tink::subtle::Random; using ::crypto::tink::test::IsOk; using ::crypto::tink::test::StatusIs; using ::google::crypto::tink::Ed25519KeyFormat; +using ::google::crypto::tink::KeyData; using ::google::crypto::tink::OutputPrefixType; using ::testing::Eq; using ::testing::IsTrue; using ::testing::NotNull; +using ::testing::SizeIs; using ::testing::TestWithParam; using ::testing::Values; @@ -153,25 +163,6 @@ TEST_F(Ed25519ProtoSerializationTest, ParseParametersWithInvalidVersion) { EXPECT_THAT(params.status(), StatusIs(absl::StatusCode::kInvalidArgument)); } -TEST_F(Ed25519ProtoSerializationTest, ParseParametersWithWrongTypeUrl) { - ASSERT_THAT(RegisterEd25519ProtoSerialization(), IsOk()); - - Ed25519KeyFormat key_format_proto; - key_format_proto.set_version(0); - - // TODO(b/280321781): Switch to public key URL and expect invalid argument. - util::StatusOr<internal::ProtoParametersSerialization> serialization = - internal::ProtoParametersSerialization::Create( - "type.googleapis.com/google.crypto.tink.WrongTypeUrl", - OutputPrefixType::RAW, key_format_proto.SerializeAsString()); - ASSERT_THAT(serialization, IsOk()); - - util::StatusOr<std::unique_ptr<Parameters>> params = - internal::MutableSerializationRegistry::GlobalInstance().ParseParameters( - *serialization); - EXPECT_THAT(params.status(), StatusIs(absl::StatusCode::kNotFound)); -} - TEST_P(Ed25519ProtoSerializationTest, SerializeParameters) { TestCase test_case = GetParam(); ASSERT_THAT(RegisterEd25519ProtoSerialization(), IsOk()); @@ -204,6 +195,128 @@ TEST_P(Ed25519ProtoSerializationTest, SerializeParameters) { EXPECT_THAT(key_format.version(), Eq(0)); } +TEST_P(Ed25519ProtoSerializationTest, ParsePublicKey) { + TestCase test_case = GetParam(); + ASSERT_THAT(RegisterEd25519ProtoSerialization(), IsOk()); + + std::string raw_key_bytes = Random::GetRandomBytes(32); + google::crypto::tink::Ed25519PublicKey key_proto; + key_proto.set_version(0); + key_proto.set_key_value(raw_key_bytes); + RestrictedData serialized_key = RestrictedData( + key_proto.SerializeAsString(), InsecureSecretKeyAccess::Get()); + + util::StatusOr<internal::ProtoKeySerialization> serialization = + internal::ProtoKeySerialization::Create( + "type.googleapis.com/google.crypto.tink.Ed25519PublicKey", + serialized_key, KeyData::ASYMMETRIC_PUBLIC, + test_case.output_prefix_type, test_case.id); + ASSERT_THAT(serialization, IsOk()); + + util::StatusOr<std::unique_ptr<Key>> key = + internal::MutableSerializationRegistry::GlobalInstance().ParseKey( + *serialization, /*token=*/absl::nullopt); + ASSERT_THAT(key, IsOk()); + EXPECT_THAT((*key)->GetIdRequirement(), Eq(test_case.id)); + EXPECT_THAT((*key)->GetParameters().HasIdRequirement(), + test_case.id.has_value()); + + util::StatusOr<Ed25519Parameters> expected_parameters = + Ed25519Parameters::Create(test_case.variant); + ASSERT_THAT(expected_parameters, IsOk()); + + util::StatusOr<Ed25519PublicKey> expected_key = Ed25519PublicKey::Create( + *expected_parameters, raw_key_bytes, test_case.id, GetPartialKeyAccess()); + ASSERT_THAT(expected_key, IsOk()); + + EXPECT_THAT(**key, Eq(*expected_key)); +} + +TEST_F(Ed25519ProtoSerializationTest, ParsePublicKeyWithInvalidSerialization) { + ASSERT_THAT(RegisterEd25519ProtoSerialization(), IsOk()); + + RestrictedData serialized_key = + RestrictedData("invalid_serialization", InsecureSecretKeyAccess::Get()); + + util::StatusOr<internal::ProtoKeySerialization> serialization = + internal::ProtoKeySerialization::Create( + "type.googleapis.com/google.crypto.tink.Ed25519PublicKey", + serialized_key, KeyData::ASYMMETRIC_PUBLIC, OutputPrefixType::TINK, + /*id_requirement=*/0x23456789); + ASSERT_THAT(serialization, IsOk()); + + util::StatusOr<std::unique_ptr<Key>> key = + internal::MutableSerializationRegistry::GlobalInstance().ParseKey( + *serialization, InsecureSecretKeyAccess::Get()); + EXPECT_THAT(key.status(), StatusIs(absl::StatusCode::kInvalidArgument)); +} + +TEST_F(Ed25519ProtoSerializationTest, ParsePublicKeyWithInvalidVersion) { + ASSERT_THAT(RegisterEd25519ProtoSerialization(), IsOk()); + + std::string raw_key_bytes = Random::GetRandomBytes(32); + google::crypto::tink::Ed25519PublicKey key_proto; + key_proto.set_version(1); // Invalid version number. + key_proto.set_key_value(raw_key_bytes); + RestrictedData serialized_key = RestrictedData( + key_proto.SerializeAsString(), InsecureSecretKeyAccess::Get()); + + util::StatusOr<internal::ProtoKeySerialization> serialization = + internal::ProtoKeySerialization::Create( + "type.googleapis.com/google.crypto.tink.Ed25519PublicKey", + serialized_key, KeyData::ASYMMETRIC_PUBLIC, OutputPrefixType::TINK, + /*id_requirement=*/0x23456789); + ASSERT_THAT(serialization, IsOk()); + + util::StatusOr<std::unique_ptr<Key>> key = + internal::MutableSerializationRegistry::GlobalInstance().ParseKey( + *serialization, /*token=*/absl::nullopt); + EXPECT_THAT(key.status(), StatusIs(absl::StatusCode::kInvalidArgument)); +} + +TEST_P(Ed25519ProtoSerializationTest, SerializePublicKey) { + TestCase test_case = GetParam(); + ASSERT_THAT(RegisterEd25519ProtoSerialization(), IsOk()); + + util::StatusOr<Ed25519Parameters> parameters = + Ed25519Parameters::Create(test_case.variant); + ASSERT_THAT(parameters, IsOk()); + + std::string raw_key_bytes = Random::GetRandomBytes(32); + util::StatusOr<Ed25519PublicKey> key = Ed25519PublicKey::Create( + *parameters, raw_key_bytes, test_case.id, GetPartialKeyAccess()); + ASSERT_THAT(key, IsOk()); + + util::StatusOr<std::unique_ptr<Serialization>> serialization = + internal::MutableSerializationRegistry::GlobalInstance() + .SerializeKey<internal::ProtoKeySerialization>( + *key, /*token=*/absl::nullopt); + ASSERT_THAT(serialization, IsOk()); + EXPECT_THAT((*serialization)->ObjectIdentifier(), + Eq("type.googleapis.com/google.crypto.tink.Ed25519PublicKey")); + + const internal::ProtoKeySerialization* proto_serialization = + dynamic_cast<const internal::ProtoKeySerialization*>( + serialization->get()); + ASSERT_THAT(proto_serialization, NotNull()); + EXPECT_THAT(proto_serialization->TypeUrl(), + Eq("type.googleapis.com/google.crypto.tink.Ed25519PublicKey")); + EXPECT_THAT(proto_serialization->KeyMaterialType(), + Eq(KeyData::ASYMMETRIC_PUBLIC)); + EXPECT_THAT(proto_serialization->GetOutputPrefixType(), + Eq(test_case.output_prefix_type)); + EXPECT_THAT(proto_serialization->IdRequirement(), Eq(test_case.id)); + + google::crypto::tink::Ed25519PublicKey proto_key; + // OSS proto library complains if input is not converted to a string. + ASSERT_THAT(proto_key.ParseFromString(std::string( + proto_serialization->SerializedKeyProto().GetSecret( + InsecureSecretKeyAccess::Get()))), + IsTrue()); + EXPECT_THAT(proto_key.version(), Eq(0)); + EXPECT_THAT(proto_key.key_value(), SizeIs(32)); +} + } // namespace } // namespace tink } // namespace crypto |