aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwconner <wconner@google.com>2023-08-03 11:43:13 -0700
committerCopybara-Service <copybara-worker@google.com>2023-08-03 11:44:16 -0700
commit89464905f119362ea232f2e094cccb5eb80150bc (patch)
tree89da1370f55168a3b1ebffc507bb19c35655fb84
parent205beaacc61da00252f5047220dd527e3128a98e (diff)
downloadtink-89464905f119362ea232f2e094cccb5eb80150bc.tar.gz
Add Ed25519 parameters proto parser and serializer.
PiperOrigin-RevId: 553543550
-rw-r--r--cc/signature/BUILD.bazel40
-rw-r--r--cc/signature/CMakeLists.txt39
-rw-r--r--cc/signature/ed25519_proto_serialization.cc152
-rw-r--r--cc/signature/ed25519_proto_serialization.h31
-rw-r--r--cc/signature/ed25519_proto_serialization_test.cc209
5 files changed, 471 insertions, 0 deletions
diff --git a/cc/signature/BUILD.bazel b/cc/signature/BUILD.bazel
index 5dd6b13ec..b5a549e31 100644
--- a/cc/signature/BUILD.bazel
+++ b/cc/signature/BUILD.bazel
@@ -479,6 +479,26 @@ cc_library(
],
)
+cc_library(
+ name = "ed25519_proto_serialization",
+ srcs = ["ed25519_proto_serialization.cc"],
+ hdrs = ["ed25519_proto_serialization.h"],
+ include_prefix = "tink/signature",
+ deps = [
+ ":ed25519_parameters",
+ "//internal:mutable_serialization_registry",
+ "//internal:parameters_parser",
+ "//internal:parameters_serializer",
+ "//internal:proto_parameters_serialization",
+ "//proto:ed25519_cc_proto",
+ "//proto:tink_cc_proto",
+ "//util:status",
+ "//util:statusor",
+ "@com_google_absl//absl/status",
+ "@com_google_absl//absl/strings",
+ ],
+)
+
# tests
cc_test(
@@ -890,3 +910,23 @@ cc_test(
"@com_google_googletest//:gtest_main",
],
)
+
+cc_test(
+ name = "ed25519_proto_serialization_test",
+ srcs = ["ed25519_proto_serialization_test.cc"],
+ deps = [
+ ":ed25519_parameters",
+ ":ed25519_proto_serialization",
+ "//:parameters",
+ "//internal:mutable_serialization_registry",
+ "//internal:proto_parameters_serialization",
+ "//internal:serialization",
+ "//proto:ed25519_cc_proto",
+ "//proto:tink_cc_proto",
+ "//util:statusor",
+ "//util:test_matchers",
+ "@com_google_absl//absl/status",
+ "@com_google_absl//absl/types:optional",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
diff --git a/cc/signature/CMakeLists.txt b/cc/signature/CMakeLists.txt
index 4e3864862..778fd63e4 100644
--- a/cc/signature/CMakeLists.txt
+++ b/cc/signature/CMakeLists.txt
@@ -456,6 +456,25 @@ tink_cc_library(
tink::util::statusor
)
+tink_cc_library(
+ NAME ed25519_proto_serialization
+ SRCS
+ ed25519_proto_serialization.cc
+ ed25519_proto_serialization.h
+ DEPS
+ tink::signature::ed25519_parameters
+ absl::status
+ absl::strings
+ 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::ed25519_cc_proto
+ tink::proto::tink_cc_proto
+)
+
# tests
tink_cc_test(
@@ -851,3 +870,23 @@ tink_cc_test(
tink::util::statusor
tink::util::test_matchers
)
+
+tink_cc_test(
+ NAME ed25519_proto_serialization_test
+ SRCS
+ ed25519_proto_serialization_test.cc
+ DEPS
+ tink::signature::ed25519_parameters
+ tink::signature::ed25519_proto_serialization
+ gmock
+ absl::status
+ absl::optional
+ 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::ed25519_cc_proto
+ tink::proto::tink_cc_proto
+)
diff --git a/cc/signature/ed25519_proto_serialization.cc b/cc/signature/ed25519_proto_serialization.cc
new file mode 100644
index 000000000..fc022c0cb
--- /dev/null
+++ b/cc/signature/ed25519_proto_serialization.cc
@@ -0,0 +1,152 @@
+// 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/ed25519_proto_serialization.h"
+
+#include "absl/status/status.h"
+#include "absl/strings/string_view.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/ed25519_parameters.h"
+#include "tink/util/status.h"
+#include "tink/util/statusor.h"
+#include "proto/ed25519.pb.h"
+#include "proto/tink.pb.h"
+
+namespace crypto {
+namespace tink {
+namespace {
+
+using ::google::crypto::tink::Ed25519KeyFormat;
+using ::google::crypto::tink::OutputPrefixType;
+
+using Ed25519ProtoParametersParserImpl =
+ internal::ParametersParserImpl<internal::ProtoParametersSerialization,
+ Ed25519Parameters>;
+using Ed25519ProtoParametersSerializerImpl =
+ internal::ParametersSerializerImpl<Ed25519Parameters,
+ internal::ProtoParametersSerialization>;
+
+const absl::string_view kPrivateTypeUrl =
+ "type.googleapis.com/google.crypto.tink.Ed25519PrivateKey";
+
+util::StatusOr<Ed25519Parameters::Variant> ToVariant(
+ OutputPrefixType output_prefix_type) {
+ switch (output_prefix_type) {
+ case OutputPrefixType::LEGACY:
+ return Ed25519Parameters::Variant::kLegacy;
+ case OutputPrefixType::CRUNCHY:
+ return Ed25519Parameters::Variant::kCrunchy;
+ case OutputPrefixType::RAW:
+ return Ed25519Parameters::Variant::kNoPrefix;
+ case OutputPrefixType::TINK:
+ return Ed25519Parameters::Variant::kTink;
+ default:
+ return util::Status(absl::StatusCode::kInvalidArgument,
+ "Could not determine Ed25519Parameters::Variant");
+ }
+}
+
+util::StatusOr<OutputPrefixType> ToOutputPrefixType(
+ Ed25519Parameters::Variant variant) {
+ switch (variant) {
+ case Ed25519Parameters::Variant::kLegacy:
+ return OutputPrefixType::LEGACY;
+ case Ed25519Parameters::Variant::kCrunchy:
+ return OutputPrefixType::CRUNCHY;
+ case Ed25519Parameters::Variant::kNoPrefix:
+ return OutputPrefixType::RAW;
+ case Ed25519Parameters::Variant::kTink:
+ return OutputPrefixType::TINK;
+ default:
+ return util::Status(absl::StatusCode::kInvalidArgument,
+ "Could not determine output prefix type");
+ }
+}
+
+util::StatusOr<Ed25519Parameters> ParseParameters(
+ const internal::ProtoParametersSerialization& serialization) {
+ if (serialization.GetKeyTemplate().type_url() != kPrivateTypeUrl) {
+ return util::Status(absl::StatusCode::kInvalidArgument,
+ "Wrong type URL when parsing Ed25519Parameters.");
+ }
+
+ Ed25519KeyFormat proto_key_format;
+ if (!proto_key_format.ParseFromString(
+ serialization.GetKeyTemplate().value())) {
+ return util::Status(absl::StatusCode::kInvalidArgument,
+ "Failed to parse Ed25519KeyFormat proto");
+ }
+ if (proto_key_format.version() != 0) {
+ return util::Status(absl::StatusCode::kInvalidArgument,
+ "Only version 0 keys are accepted.");
+ }
+
+ util::StatusOr<Ed25519Parameters::Variant> variant =
+ ToVariant(serialization.GetKeyTemplate().output_prefix_type());
+ if (!variant.ok()) {
+ return variant.status();
+ }
+
+ return Ed25519Parameters::Create(*variant);
+}
+
+util::StatusOr<internal::ProtoParametersSerialization> SerializeParameters(
+ const Ed25519Parameters& parameters) {
+ util::StatusOr<OutputPrefixType> output_prefix_type =
+ ToOutputPrefixType(parameters.GetVariant());
+ if (!output_prefix_type.ok()) {
+ return output_prefix_type.status();
+ }
+
+ Ed25519KeyFormat proto_key_format;
+ proto_key_format.set_version(0);
+
+ return internal::ProtoParametersSerialization::Create(
+ kPrivateTypeUrl, *output_prefix_type,
+ proto_key_format.SerializeAsString());
+}
+
+Ed25519ProtoParametersParserImpl* Ed25519ProtoParametersParser() {
+ static auto* parser =
+ new Ed25519ProtoParametersParserImpl(kPrivateTypeUrl, ParseParameters);
+ return parser;
+}
+
+Ed25519ProtoParametersSerializerImpl* Ed25519ProtoParametersSerializer() {
+ static auto* serializer = new Ed25519ProtoParametersSerializerImpl(
+ kPrivateTypeUrl, SerializeParameters);
+ return serializer;
+}
+
+} // namespace
+
+util::Status RegisterEd25519ProtoSerialization() {
+ util::Status status =
+ internal::MutableSerializationRegistry::GlobalInstance()
+ .RegisterParametersParser(Ed25519ProtoParametersParser());
+ if (!status.ok()) {
+ return status;
+ }
+
+ return internal::MutableSerializationRegistry::GlobalInstance()
+ .RegisterParametersSerializer(Ed25519ProtoParametersSerializer());
+}
+
+} // namespace tink
+} // namespace crypto
diff --git a/cc/signature/ed25519_proto_serialization.h b/cc/signature/ed25519_proto_serialization.h
new file mode 100644
index 000000000..6f2527e19
--- /dev/null
+++ b/cc/signature/ed25519_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_ED25519_PROTO_SERIALIZATION_H_
+#define TINK_SIGNATURE_ED25519_PROTO_SERIALIZATION_H_
+
+#include "tink/util/status.h"
+
+namespace crypto {
+namespace tink {
+
+// Registers proto parsers and serializers for Ed25519 parameters and keys.
+crypto::tink::util::Status RegisterEd25519ProtoSerialization();
+
+} // namespace tink
+} // namespace crypto
+
+#endif // TINK_SIGNATURE_ED25519_PROTO_SERIALIZATION_H_
diff --git a/cc/signature/ed25519_proto_serialization_test.cc b/cc/signature/ed25519_proto_serialization_test.cc
new file mode 100644
index 000000000..a2730c57d
--- /dev/null
+++ b/cc/signature/ed25519_proto_serialization_test.cc
@@ -0,0 +1,209 @@
+// 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/ed25519_proto_serialization.h"
+
+#include <memory>
+#include <string>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/status/status.h"
+#include "absl/types/optional.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/ed25519_parameters.h"
+#include "tink/util/statusor.h"
+#include "tink/util/test_matchers.h"
+#include "proto/ed25519.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::Ed25519KeyFormat;
+using ::google::crypto::tink::OutputPrefixType;
+using ::testing::Eq;
+using ::testing::IsTrue;
+using ::testing::NotNull;
+using ::testing::TestWithParam;
+using ::testing::Values;
+
+struct TestCase {
+ Ed25519Parameters::Variant variant;
+ OutputPrefixType output_prefix_type;
+ absl::optional<int> id;
+ std::string output_prefix;
+};
+
+class Ed25519ProtoSerializationTest : public TestWithParam<TestCase> {
+ protected:
+ void SetUp() override {
+ internal::MutableSerializationRegistry::GlobalInstance().Reset();
+ }
+};
+
+INSTANTIATE_TEST_SUITE_P(
+ Ed25519ProtoSerializationTestSuite, Ed25519ProtoSerializationTest,
+ Values(TestCase{Ed25519Parameters::Variant::kTink, OutputPrefixType::TINK,
+ /*id=*/0x02030400,
+ /*output_prefix=*/std::string("\x01\x02\x03\x04\x00", 5)},
+ TestCase{Ed25519Parameters::Variant::kCrunchy,
+ OutputPrefixType::CRUNCHY, /*id=*/0x01030005,
+ /*output_prefix=*/std::string("\x00\x01\x03\x00\x05", 5)},
+ TestCase{Ed25519Parameters::Variant::kLegacy,
+ OutputPrefixType::LEGACY, /*id=*/0x07080910,
+ /*output_prefix=*/std::string("\x00\x07\x08\x09\x10", 5)},
+ TestCase{Ed25519Parameters::Variant::kNoPrefix,
+ OutputPrefixType::RAW, /*id=*/absl::nullopt,
+ /*output_prefix=*/""}));
+
+TEST_P(Ed25519ProtoSerializationTest, ParseParameters) {
+ TestCase test_case = GetParam();
+ ASSERT_THAT(RegisterEd25519ProtoSerialization(), IsOk());
+
+ Ed25519KeyFormat key_format_proto;
+ key_format_proto.set_version(0);
+
+ util::StatusOr<internal::ProtoParametersSerialization> serialization =
+ internal::ProtoParametersSerialization::Create(
+ "type.googleapis.com/google.crypto.tink.Ed25519PrivateKey",
+ test_case.output_prefix_type, key_format_proto.SerializeAsString());
+ ASSERT_THAT(serialization, IsOk());
+
+ util::StatusOr<std::unique_ptr<Parameters>> params =
+ internal::MutableSerializationRegistry::GlobalInstance().ParseParameters(
+ *serialization);
+ ASSERT_THAT(params, IsOk());
+ EXPECT_THAT((*params)->HasIdRequirement(), test_case.id.has_value());
+
+ const Ed25519Parameters* ed25519_params =
+ dynamic_cast<const Ed25519Parameters*>(params->get());
+ ASSERT_THAT(ed25519_params, NotNull());
+ EXPECT_THAT(ed25519_params->GetVariant(), Eq(test_case.variant));
+}
+
+TEST_F(Ed25519ProtoSerializationTest, ParseParametersWithInvalidSerialization) {
+ ASSERT_THAT(RegisterEd25519ProtoSerialization(), IsOk());
+
+ util::StatusOr<internal::ProtoParametersSerialization> serialization =
+ internal::ProtoParametersSerialization::Create(
+ "type.googleapis.com/google.crypto.tink.Ed25519PrivateKey",
+ OutputPrefixType::RAW, "invalid_serialization");
+ ASSERT_THAT(serialization, IsOk());
+
+ util::StatusOr<std::unique_ptr<Parameters>> params =
+ internal::MutableSerializationRegistry::GlobalInstance().ParseParameters(
+ *serialization);
+ EXPECT_THAT(params.status(), StatusIs(absl::StatusCode::kInvalidArgument));
+}
+
+TEST_F(Ed25519ProtoSerializationTest, ParseParametersWithUnkownOutputPrefix) {
+ ASSERT_THAT(RegisterEd25519ProtoSerialization(), IsOk());
+
+ Ed25519KeyFormat key_format_proto;
+ key_format_proto.set_version(0);
+
+ util::StatusOr<internal::ProtoParametersSerialization> serialization =
+ internal::ProtoParametersSerialization::Create(
+ "type.googleapis.com/google.crypto.tink.Ed25519PrivateKey",
+ OutputPrefixType::UNKNOWN_PREFIX,
+ 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::kInvalidArgument));
+}
+
+TEST_F(Ed25519ProtoSerializationTest, ParseParametersWithInvalidVersion) {
+ ASSERT_THAT(RegisterEd25519ProtoSerialization(), IsOk());
+
+ Ed25519KeyFormat key_format_proto;
+ key_format_proto.set_version(1);
+
+ util::StatusOr<internal::ProtoParametersSerialization> serialization =
+ internal::ProtoParametersSerialization::Create(
+ "type.googleapis.com/google.crypto.tink.Ed25519PrivateKey",
+ 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::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());
+
+ util::StatusOr<Ed25519Parameters> parameters =
+ Ed25519Parameters::Create(test_case.variant);
+ ASSERT_THAT(parameters, IsOk());
+
+ util::StatusOr<std::unique_ptr<Serialization>> serialization =
+ internal::MutableSerializationRegistry::GlobalInstance()
+ .SerializeParameters<internal::ProtoParametersSerialization>(
+ *parameters);
+ ASSERT_THAT(serialization, IsOk());
+ EXPECT_THAT((*serialization)->ObjectIdentifier(),
+ Eq("type.googleapis.com/google.crypto.tink.Ed25519PrivateKey"));
+
+ const internal::ProtoParametersSerialization* proto_serialization =
+ dynamic_cast<const internal::ProtoParametersSerialization*>(
+ serialization->get());
+ ASSERT_THAT(proto_serialization, NotNull());
+ EXPECT_THAT(proto_serialization->GetKeyTemplate().type_url(),
+ Eq("type.googleapis.com/google.crypto.tink.Ed25519PrivateKey"));
+ EXPECT_THAT(proto_serialization->GetKeyTemplate().output_prefix_type(),
+ Eq(test_case.output_prefix_type));
+
+ Ed25519KeyFormat key_format;
+ ASSERT_THAT(
+ key_format.ParseFromString(proto_serialization->GetKeyTemplate().value()),
+ IsTrue());
+ EXPECT_THAT(key_format.version(), Eq(0));
+}
+
+} // namespace
+} // namespace tink
+} // namespace crypto