aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwconner <wconner@google.com>2023-08-04 04:31:00 -0700
committerCopybara-Service <copybara-worker@google.com>2023-08-04 04:32:38 -0700
commit4fa7e0322848bcf34eb200510da0619ae0b3636b (patch)
treef7f89649378d7f0ab53d098a44c2d370427a2ec5
parent89464905f119362ea232f2e094cccb5eb80150bc (diff)
downloadtink-4fa7e0322848bcf34eb200510da0619ae0b3636b.tar.gz
Add Ed25519 public key proto parsers and serializers.
PiperOrigin-RevId: 553766329
-rw-r--r--cc/signature/BUILD.bazel16
-rw-r--r--cc/signature/CMakeLists.txt16
-rw-r--r--cc/signature/ed25519_proto_serialization.cc107
-rw-r--r--cc/signature/ed25519_proto_serialization_test.cc151
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