xref: /aosp_15_r20/external/tink/cc/signature/ed25519_proto_serialization.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1 // Copyright 2023 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 ////////////////////////////////////////////////////////////////////////////////
16 
17 #include "tink/signature/ed25519_proto_serialization.h"
18 
19 #include <string>
20 
21 #include "absl/status/status.h"
22 #include "absl/strings/string_view.h"
23 #include "absl/types/optional.h"
24 #include "tink/insecure_secret_key_access.h"
25 #include "tink/internal/key_parser.h"
26 #include "tink/internal/key_serializer.h"
27 #include "tink/internal/mutable_serialization_registry.h"
28 #include "tink/internal/parameters_parser.h"
29 #include "tink/internal/parameters_serializer.h"
30 #include "tink/internal/proto_key_serialization.h"
31 #include "tink/internal/proto_parameters_serialization.h"
32 #include "tink/partial_key_access.h"
33 #include "tink/restricted_data.h"
34 #include "tink/secret_key_access_token.h"
35 #include "tink/signature/ed25519_parameters.h"
36 #include "tink/signature/ed25519_private_key.h"
37 #include "tink/signature/ed25519_public_key.h"
38 #include "tink/util/status.h"
39 #include "tink/util/statusor.h"
40 #include "proto/ed25519.pb.h"
41 #include "proto/tink.pb.h"
42 
43 namespace crypto {
44 namespace tink {
45 namespace {
46 
47 using ::google::crypto::tink::Ed25519KeyFormat;
48 using ::google::crypto::tink::KeyData;
49 using ::google::crypto::tink::OutputPrefixType;
50 
51 using Ed25519ProtoParametersParserImpl =
52     internal::ParametersParserImpl<internal::ProtoParametersSerialization,
53                                    Ed25519Parameters>;
54 using Ed25519ProtoParametersSerializerImpl =
55     internal::ParametersSerializerImpl<Ed25519Parameters,
56                                        internal::ProtoParametersSerialization>;
57 using Ed25519ProtoPublicKeyParserImpl =
58     internal::KeyParserImpl<internal::ProtoKeySerialization, Ed25519PublicKey>;
59 using Ed25519ProtoPublicKeySerializerImpl =
60     internal::KeySerializerImpl<Ed25519PublicKey,
61                                 internal::ProtoKeySerialization>;
62 using Ed25519ProtoPrivateKeyParserImpl =
63     internal::KeyParserImpl<internal::ProtoKeySerialization, Ed25519PrivateKey>;
64 using Ed25519ProtoPrivateKeySerializerImpl =
65     internal::KeySerializerImpl<Ed25519PrivateKey,
66                                 internal::ProtoKeySerialization>;
67 
68 const absl::string_view kPublicTypeUrl =
69     "type.googleapis.com/google.crypto.tink.Ed25519PublicKey";
70 const absl::string_view kPrivateTypeUrl =
71     "type.googleapis.com/google.crypto.tink.Ed25519PrivateKey";
72 
ToVariant(OutputPrefixType output_prefix_type)73 util::StatusOr<Ed25519Parameters::Variant> ToVariant(
74     OutputPrefixType output_prefix_type) {
75   switch (output_prefix_type) {
76     case OutputPrefixType::LEGACY:
77       return Ed25519Parameters::Variant::kLegacy;
78     case OutputPrefixType::CRUNCHY:
79       return Ed25519Parameters::Variant::kCrunchy;
80     case OutputPrefixType::RAW:
81       return Ed25519Parameters::Variant::kNoPrefix;
82     case OutputPrefixType::TINK:
83       return Ed25519Parameters::Variant::kTink;
84     default:
85       return util::Status(absl::StatusCode::kInvalidArgument,
86                           "Could not determine Ed25519Parameters::Variant");
87   }
88 }
89 
ToOutputPrefixType(Ed25519Parameters::Variant variant)90 util::StatusOr<OutputPrefixType> ToOutputPrefixType(
91     Ed25519Parameters::Variant variant) {
92   switch (variant) {
93     case Ed25519Parameters::Variant::kLegacy:
94       return OutputPrefixType::LEGACY;
95     case Ed25519Parameters::Variant::kCrunchy:
96       return OutputPrefixType::CRUNCHY;
97     case Ed25519Parameters::Variant::kNoPrefix:
98       return OutputPrefixType::RAW;
99     case Ed25519Parameters::Variant::kTink:
100       return OutputPrefixType::TINK;
101     default:
102       return util::Status(absl::StatusCode::kInvalidArgument,
103                           "Could not determine output prefix type");
104   }
105 }
106 
ParseParameters(const internal::ProtoParametersSerialization & serialization)107 util::StatusOr<Ed25519Parameters> ParseParameters(
108     const internal::ProtoParametersSerialization& serialization) {
109   if (serialization.GetKeyTemplate().type_url() != kPrivateTypeUrl) {
110     return util::Status(absl::StatusCode::kInvalidArgument,
111                         "Wrong type URL when parsing Ed25519Parameters.");
112   }
113 
114   Ed25519KeyFormat proto_key_format;
115   if (!proto_key_format.ParseFromString(
116           serialization.GetKeyTemplate().value())) {
117     return util::Status(absl::StatusCode::kInvalidArgument,
118                         "Failed to parse Ed25519KeyFormat proto");
119   }
120   if (proto_key_format.version() != 0) {
121     return util::Status(absl::StatusCode::kInvalidArgument,
122                         "Only version 0 keys are accepted.");
123   }
124 
125   util::StatusOr<Ed25519Parameters::Variant> variant =
126       ToVariant(serialization.GetKeyTemplate().output_prefix_type());
127   if (!variant.ok()) {
128     return variant.status();
129   }
130 
131   return Ed25519Parameters::Create(*variant);
132 }
133 
ParsePublicKey(const internal::ProtoKeySerialization & serialization,absl::optional<SecretKeyAccessToken> token)134 util::StatusOr<Ed25519PublicKey> ParsePublicKey(
135     const internal::ProtoKeySerialization& serialization,
136     absl::optional<SecretKeyAccessToken> token) {
137   if (serialization.TypeUrl() != kPublicTypeUrl) {
138     return util::Status(absl::StatusCode::kInvalidArgument,
139                         "Wrong type URL when parsing Ed25519PublicKey.");
140   }
141 
142   google::crypto::tink::Ed25519PublicKey proto_key;
143   RestrictedData restricted_data = serialization.SerializedKeyProto();
144   // OSS proto library complains if input is not converted to a string.
145   if (!proto_key.ParseFromString(std::string(
146           restricted_data.GetSecret(InsecureSecretKeyAccess::Get())))) {
147     return util::Status(absl::StatusCode::kInvalidArgument,
148                         "Failed to parse Ed25519PublicKey proto");
149   }
150   if (proto_key.version() != 0) {
151     return util::Status(absl::StatusCode::kInvalidArgument,
152                         "Only version 0 keys are accepted.");
153   }
154 
155   util::StatusOr<Ed25519Parameters::Variant> variant =
156       ToVariant(serialization.GetOutputPrefixType());
157   if (!variant.ok()) {
158     return variant.status();
159   }
160 
161   util::StatusOr<Ed25519Parameters> parameters =
162       Ed25519Parameters::Create(*variant);
163   if (!parameters.ok()) {
164     return parameters.status();
165   }
166 
167   return Ed25519PublicKey::Create(*parameters, proto_key.key_value(),
168                                   serialization.IdRequirement(),
169                                   GetPartialKeyAccess());
170 }
171 
ParsePrivateKey(const internal::ProtoKeySerialization & serialization,absl::optional<SecretKeyAccessToken> token)172 util::StatusOr<Ed25519PrivateKey> ParsePrivateKey(
173     const internal::ProtoKeySerialization& serialization,
174     absl::optional<SecretKeyAccessToken> token) {
175   if (serialization.TypeUrl() != kPrivateTypeUrl) {
176     return util::Status(absl::StatusCode::kInvalidArgument,
177                         "Wrong type URL when parsing Ed25519PrivateKey.");
178   }
179   if (!token.has_value()) {
180     return util::Status(absl::StatusCode::kPermissionDenied,
181                         "SecretKeyAccess is required");
182   }
183   google::crypto::tink::Ed25519PrivateKey proto_key;
184   RestrictedData restricted_data = serialization.SerializedKeyProto();
185   // OSS proto library complains if input is not converted to a string.
186   if (!proto_key.ParseFromString(
187           std::string(restricted_data.GetSecret(*token)))) {
188     return util::Status(absl::StatusCode::kInvalidArgument,
189                         "Failed to parse Ed25519PrivateKey proto");
190   }
191   if (proto_key.version() != 0) {
192     return util::Status(absl::StatusCode::kInvalidArgument,
193                         "Only version 0 keys are accepted.");
194   }
195 
196   util::StatusOr<Ed25519Parameters::Variant> variant =
197       ToVariant(serialization.GetOutputPrefixType());
198   if (!variant.ok()) {
199     return variant.status();
200   }
201 
202   util::StatusOr<Ed25519Parameters> parameters =
203       Ed25519Parameters::Create(*variant);
204   if (!parameters.ok()) {
205     return parameters.status();
206   }
207 
208   util::StatusOr<Ed25519PublicKey> public_key = Ed25519PublicKey::Create(
209       *parameters, proto_key.public_key().key_value(),
210       serialization.IdRequirement(), GetPartialKeyAccess());
211   if (!public_key.ok()) {
212     return public_key.status();
213   }
214 
215   return Ed25519PrivateKey::Create(
216       *public_key, RestrictedData(proto_key.key_value(), *token),
217       GetPartialKeyAccess());
218 }
219 
SerializeParameters(const Ed25519Parameters & parameters)220 util::StatusOr<internal::ProtoParametersSerialization> SerializeParameters(
221     const Ed25519Parameters& parameters) {
222   util::StatusOr<OutputPrefixType> output_prefix_type =
223       ToOutputPrefixType(parameters.GetVariant());
224   if (!output_prefix_type.ok()) {
225     return output_prefix_type.status();
226   }
227 
228   Ed25519KeyFormat proto_key_format;
229   proto_key_format.set_version(0);
230 
231   return internal::ProtoParametersSerialization::Create(
232       kPrivateTypeUrl, *output_prefix_type,
233       proto_key_format.SerializeAsString());
234 }
235 
SerializePublicKey(const Ed25519PublicKey & key,absl::optional<SecretKeyAccessToken> token)236 util::StatusOr<internal::ProtoKeySerialization> SerializePublicKey(
237     const Ed25519PublicKey& key, absl::optional<SecretKeyAccessToken> token) {
238   google::crypto::tink::Ed25519PublicKey proto_key;
239   proto_key.set_version(0);
240   // OSS proto library complains if input is not converted to a string.
241   proto_key.set_key_value(
242       std::string(key.GetPublicKeyBytes(GetPartialKeyAccess())));
243 
244   util::StatusOr<OutputPrefixType> output_prefix_type =
245       ToOutputPrefixType(key.GetParameters().GetVariant());
246   if (!output_prefix_type.ok()) {
247     return output_prefix_type.status();
248   }
249 
250   RestrictedData restricted_output = RestrictedData(
251       proto_key.SerializeAsString(), InsecureSecretKeyAccess::Get());
252   return internal::ProtoKeySerialization::Create(
253       kPublicTypeUrl, restricted_output, KeyData::ASYMMETRIC_PUBLIC,
254       *output_prefix_type, key.GetIdRequirement());
255 }
256 
SerializePrivateKey(const Ed25519PrivateKey & key,absl::optional<SecretKeyAccessToken> token)257 util::StatusOr<internal::ProtoKeySerialization> SerializePrivateKey(
258     const Ed25519PrivateKey& key, absl::optional<SecretKeyAccessToken> token) {
259   util::StatusOr<RestrictedData> restricted_input =
260       key.GetPrivateKeyBytes(GetPartialKeyAccess());
261   if (!restricted_input.ok()) {
262     return restricted_input.status();
263   }
264   if (!token.has_value()) {
265     return util::Status(absl::StatusCode::kPermissionDenied,
266                         "SecretKeyAccess is required");
267   }
268 
269   google::crypto::tink::Ed25519PublicKey proto_public_key;
270   proto_public_key.set_version(0);
271   // OSS proto library complains if input is not converted to a string.
272   proto_public_key.set_key_value(
273       std::string(key.GetPublicKey().GetPublicKeyBytes(GetPartialKeyAccess())));
274 
275   google::crypto::tink::Ed25519PrivateKey proto_private_key;
276   proto_private_key.set_version(0);
277   *proto_private_key.mutable_public_key() = proto_public_key;
278   // OSS proto library complains if input is not converted to a string.
279   proto_private_key.set_key_value(
280       std::string(restricted_input->GetSecret(*token)));
281 
282   util::StatusOr<OutputPrefixType> output_prefix_type =
283       ToOutputPrefixType(key.GetPublicKey().GetParameters().GetVariant());
284   if (!output_prefix_type.ok()) {
285     return output_prefix_type.status();
286   }
287 
288   RestrictedData restricted_output =
289       RestrictedData(proto_private_key.SerializeAsString(), *token);
290   return internal::ProtoKeySerialization::Create(
291       kPrivateTypeUrl, restricted_output, KeyData::ASYMMETRIC_PRIVATE,
292       *output_prefix_type, key.GetIdRequirement());
293 }
294 
Ed25519ProtoParametersParser()295 Ed25519ProtoParametersParserImpl* Ed25519ProtoParametersParser() {
296   static auto* parser =
297       new Ed25519ProtoParametersParserImpl(kPrivateTypeUrl, ParseParameters);
298   return parser;
299 }
300 
Ed25519ProtoParametersSerializer()301 Ed25519ProtoParametersSerializerImpl* Ed25519ProtoParametersSerializer() {
302   static auto* serializer = new Ed25519ProtoParametersSerializerImpl(
303       kPrivateTypeUrl, SerializeParameters);
304   return serializer;
305 }
306 
Ed25519ProtoPublicKeyParser()307 Ed25519ProtoPublicKeyParserImpl* Ed25519ProtoPublicKeyParser() {
308   static auto* parser =
309       new Ed25519ProtoPublicKeyParserImpl(kPublicTypeUrl, ParsePublicKey);
310   return parser;
311 }
312 
Ed25519ProtoPublicKeySerializer()313 Ed25519ProtoPublicKeySerializerImpl* Ed25519ProtoPublicKeySerializer() {
314   static auto* serializer =
315       new Ed25519ProtoPublicKeySerializerImpl(SerializePublicKey);
316   return serializer;
317 }
318 
Ed25519ProtoPrivateKeyParser()319 Ed25519ProtoPrivateKeyParserImpl* Ed25519ProtoPrivateKeyParser() {
320   static auto* parser =
321       new Ed25519ProtoPrivateKeyParserImpl(kPrivateTypeUrl, ParsePrivateKey);
322   return parser;
323 }
324 
Ed25519ProtoPrivateKeySerializer()325 Ed25519ProtoPrivateKeySerializerImpl* Ed25519ProtoPrivateKeySerializer() {
326   static auto* serializer =
327       new Ed25519ProtoPrivateKeySerializerImpl(SerializePrivateKey);
328   return serializer;
329 }
330 
331 }  // namespace
332 
RegisterEd25519ProtoSerialization()333 util::Status RegisterEd25519ProtoSerialization() {
334   util::Status status =
335       internal::MutableSerializationRegistry::GlobalInstance()
336           .RegisterParametersParser(Ed25519ProtoParametersParser());
337   if (!status.ok()) {
338     return status;
339   }
340 
341   status =
342       internal::MutableSerializationRegistry::GlobalInstance()
343           .RegisterParametersSerializer(Ed25519ProtoParametersSerializer());
344   if (!status.ok()) {
345     return status;
346   }
347 
348   status = internal::MutableSerializationRegistry::GlobalInstance()
349                .RegisterKeyParser(Ed25519ProtoPublicKeyParser());
350   if (!status.ok()) {
351     return status;
352   }
353 
354   status = internal::MutableSerializationRegistry::GlobalInstance()
355                .RegisterKeySerializer(Ed25519ProtoPublicKeySerializer());
356   if (!status.ok()) {
357     return status;
358   }
359 
360   status = internal::MutableSerializationRegistry::GlobalInstance()
361                .RegisterKeyParser(Ed25519ProtoPrivateKeyParser());
362   if (!status.ok()) {
363     return status;
364   }
365 
366   return internal::MutableSerializationRegistry::GlobalInstance()
367       .RegisterKeySerializer(Ed25519ProtoPrivateKeySerializer());
368 }
369 
370 }  // namespace tink
371 }  // namespace crypto
372