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