1 // Copyright 2021 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/jwt/jwk_set_converter.h"
18
19 #include <memory>
20 #include <ostream>
21 #include <sstream>
22 #include <string>
23
24 #include "absl/strings/escaping.h"
25 #include "tink/binary_keyset_writer.h"
26 #include "tink/jwt/internal/json_util.h"
27 #include "tink/jwt/internal/jwt_format.h"
28 #include "tink/jwt/jwt_public_key_sign.h"
29 #include "tink/jwt/raw_jwt.h"
30 #include "tink/keyset_handle.h"
31 #include "tink/util/keyset_util.h"
32 #include "tink/util/statusor.h"
33 #include "proto/common.pb.h"
34 #include "proto/jwt_ecdsa.pb.h"
35 #include "proto/jwt_rsa_ssa_pkcs1.pb.h"
36 #include "proto/jwt_rsa_ssa_pss.pb.h"
37 #include "proto/tink.pb.h"
38
39 namespace crypto {
40 namespace tink {
41
42 using ::google::crypto::tink::JwtRsaSsaPkcs1Algorithm;
43 using ::google::crypto::tink::JwtRsaSsaPkcs1PublicKey;
44 using ::google::crypto::tink::JwtRsaSsaPssAlgorithm;
45 using ::google::crypto::tink::JwtRsaSsaPssPublicKey;
46 using ::google::crypto::tink::JwtEcdsaAlgorithm;
47 using ::google::crypto::tink::JwtEcdsaPublicKey;
48 using ::google::crypto::tink::KeyData;
49 using ::google::crypto::tink::Keyset;
50 using ::google::crypto::tink::Keyset_Key;
51 using ::google::crypto::tink::KeyStatusType;
52 using ::google::crypto::tink::OutputPrefixType;
53 using ::google::protobuf::ListValue;
54 using ::google::protobuf::Struct;
55 using ::google::protobuf::Value;
56
57 namespace {
58
HasItem(const Struct & key_struct,absl::string_view name)59 bool HasItem(const Struct& key_struct, absl::string_view name) {
60 return key_struct.fields().find(std::string(name)) !=
61 key_struct.fields().end();
62 }
63
GetStringItem(const Struct & key_struct,absl::string_view name)64 util::StatusOr<std::string> GetStringItem(const Struct& key_struct,
65 absl::string_view name) {
66 auto it = key_struct.fields().find(std::string(name));
67 if (it == key_struct.fields().end()) {
68 return util::Status(absl::StatusCode::kInvalidArgument, "not found");
69 }
70 if (it->second.kind_case() != Value::kStringValue) {
71 return util::Status(absl::StatusCode::kInvalidArgument, "is not a string");
72 }
73 return it->second.string_value();
74 }
75
ExpectStringItem(const Struct & key_struct,absl::string_view name,absl::string_view value)76 util::Status ExpectStringItem(const Struct& key_struct, absl::string_view name,
77 absl::string_view value) {
78 util::StatusOr<std::string> item = GetStringItem(key_struct, name);
79 if (!item.ok()) {
80 return item.status();
81 }
82 if (*item != value) {
83 return util::Status(absl::StatusCode::kInvalidArgument, "unexpected value");
84 }
85 return util::OkStatus();
86 }
87
ValidateUseIsSig(const Struct & key_struct)88 util::Status ValidateUseIsSig(const Struct& key_struct) {
89 if (!HasItem(key_struct, "use")) {
90 return util::OkStatus();
91 }
92 return ExpectStringItem(key_struct, "use", "sig");
93 }
94
ValidateKeyOpsIsVerify(const Struct & key_struct)95 util::Status ValidateKeyOpsIsVerify(const Struct& key_struct) {
96 if (!HasItem(key_struct, "key_ops")) {
97 return util::OkStatus();
98 }
99 auto it = key_struct.fields().find("key_ops");
100 if (it == key_struct.fields().end()) {
101 return util::Status(absl::StatusCode::kInvalidArgument,
102 "key_ops not found");
103 }
104 if (it->second.kind_case() != Value::kListValue) {
105 return util::Status(absl::StatusCode::kInvalidArgument,
106 "key_ops is not a list");
107 }
108 const ListValue& key_ops_list = it->second.list_value();
109 if (key_ops_list.values_size() != 1) {
110 return util::Status(absl::StatusCode::kInvalidArgument,
111 "key_ops size is not 1");
112 }
113 const Value & value = key_ops_list.values().Get(0);
114 if (value.kind_case() != Value::kStringValue) {
115 return util::Status(absl::StatusCode::kInvalidArgument,
116 "key_ops item is not a string");
117 }
118 if (value.string_value() != "verify") {
119 return util::Status(absl::StatusCode::kInvalidArgument,
120 "key_ops is not equal to [\"verify\"]");
121 }
122 return util::OkStatus();
123 }
124
RsPublicKeyDataFromKeyStruct(const Struct & key_struct)125 util::StatusOr<KeyData> RsPublicKeyDataFromKeyStruct(const Struct& key_struct) {
126 JwtRsaSsaPkcs1PublicKey public_key_proto;
127 public_key_proto.set_version(0);
128
129 util::StatusOr<std::string> alg = GetStringItem(key_struct, "alg");
130 if (!alg.ok()) {
131 return alg.status();
132 }
133 if (*alg == "RS256") {
134 public_key_proto.set_algorithm(JwtRsaSsaPkcs1Algorithm::RS256);
135 } else if (*alg == "RS384") {
136 public_key_proto.set_algorithm(JwtRsaSsaPkcs1Algorithm::RS384);
137 } else if (*alg == "RS512") {
138 public_key_proto.set_algorithm(JwtRsaSsaPkcs1Algorithm::RS512);
139 } else {
140 return util::Status(absl::StatusCode::kInvalidArgument, "invalid alg");
141 }
142
143 if (HasItem(key_struct, "p") || HasItem(key_struct, "q") ||
144 HasItem(key_struct, "dq") || HasItem(key_struct, "dp") ||
145 HasItem(key_struct, "d") || HasItem(key_struct, "qi")) {
146 return util::Status(absl::StatusCode::kInvalidArgument,
147 "private keys cannot be converted");
148 }
149 util::Status status_kty = ExpectStringItem(key_struct, "kty", "RSA");
150 if (!status_kty.ok()) {
151 return status_kty;
152 }
153 util::Status status_use = ValidateUseIsSig(key_struct);
154 if (!status_use.ok()) {
155 return status_use;
156 }
157 util::Status status_key_ops = ValidateKeyOpsIsVerify(key_struct);
158 if (!status_key_ops.ok()) {
159 return status_key_ops;
160 }
161
162 util::StatusOr<std::string> e = GetStringItem(key_struct, "e");
163 if (!e.ok()) {
164 return e.status();
165 }
166 std::string decoded_e;
167 if (!absl::WebSafeBase64Unescape(*e, &decoded_e)) {
168 return util::Status(absl::StatusCode::kInvalidArgument,
169 "failed to decode e");
170 }
171 public_key_proto.set_e(decoded_e);
172
173 util::StatusOr<std::string> n = GetStringItem(key_struct, "n");
174 if (!n.ok()) {
175 return n.status();
176 }
177 std::string decoded_n;
178 if (!absl::WebSafeBase64Unescape(*n, &decoded_n)) {
179 return util::Status(absl::StatusCode::kInvalidArgument,
180 "failed to decode n");
181 }
182 public_key_proto.set_n(decoded_n);
183
184 if (HasItem(key_struct, "kid")) {
185 util::StatusOr<std::string> kid = GetStringItem(key_struct, "kid");
186 if (!kid.ok()) {
187 return kid.status();
188 }
189 public_key_proto.mutable_custom_kid()->set_value(*kid);
190 }
191 KeyData key_data_proto;
192 key_data_proto.set_type_url(
193 "type.googleapis.com/google.crypto.tink.JwtRsaSsaPkcs1PublicKey");
194 key_data_proto.set_value(public_key_proto.SerializeAsString());
195 key_data_proto.set_key_material_type(KeyData::ASYMMETRIC_PUBLIC);
196 return key_data_proto;
197 }
198
PsPublicKeyDataFromKeyStruct(const Struct & key_struct)199 util::StatusOr<KeyData> PsPublicKeyDataFromKeyStruct(const Struct& key_struct) {
200 JwtRsaSsaPssPublicKey public_key_proto;
201 public_key_proto.set_version(0);
202
203 util::StatusOr<std::string> alg = GetStringItem(key_struct, "alg");
204 if (!alg.ok()) {
205 return alg.status();
206 }
207 if (*alg == "PS256") {
208 public_key_proto.set_algorithm(JwtRsaSsaPssAlgorithm::PS256);
209 } else if (*alg == "PS384") {
210 public_key_proto.set_algorithm(JwtRsaSsaPssAlgorithm::PS384);
211 } else if (*alg == "PS512") {
212 public_key_proto.set_algorithm(JwtRsaSsaPssAlgorithm::PS512);
213 } else {
214 return util::Status(absl::StatusCode::kInvalidArgument, "invalid alg");
215 }
216
217 if (HasItem(key_struct, "p") || HasItem(key_struct, "q") ||
218 HasItem(key_struct, "dq") || HasItem(key_struct, "dp") ||
219 HasItem(key_struct, "d") || HasItem(key_struct, "qi")) {
220 return util::Status(absl::StatusCode::kInvalidArgument,
221 "private keys cannot be converted");
222 }
223 util::Status status_kty = ExpectStringItem(key_struct, "kty", "RSA");
224 if (!status_kty.ok()) {
225 return status_kty;
226 }
227 util::Status status_use = ValidateUseIsSig(key_struct);
228 if (!status_use.ok()) {
229 return status_use;
230 }
231 util::Status status_key_ops = ValidateKeyOpsIsVerify(key_struct);
232 if (!status_key_ops.ok()) {
233 return status_key_ops;
234 }
235
236 util::StatusOr<std::string> e = GetStringItem(key_struct, "e");
237 if (!e.ok()) {
238 return e.status();
239 }
240 std::string decoded_e;
241 if (!absl::WebSafeBase64Unescape(*e, &decoded_e)) {
242 return util::Status(absl::StatusCode::kInvalidArgument,
243 "failed to decode e");
244 }
245 public_key_proto.set_e(decoded_e);
246
247 util::StatusOr<std::string> n = GetStringItem(key_struct, "n");
248 if (!n.ok()) {
249 return n.status();
250 }
251 std::string decoded_n;
252 if (!absl::WebSafeBase64Unescape(*n, &decoded_n)) {
253 return util::Status(absl::StatusCode::kInvalidArgument,
254 "failed to decode n");
255 }
256 public_key_proto.set_n(decoded_n);
257
258 if (HasItem(key_struct, "kid")) {
259 util::StatusOr<std::string> kid = GetStringItem(key_struct, "kid");
260 if (!kid.ok()) {
261 return kid.status();
262 }
263 public_key_proto.mutable_custom_kid()->set_value(*kid);
264 }
265 KeyData key_data_proto;
266 key_data_proto.set_type_url(
267 "type.googleapis.com/google.crypto.tink.JwtRsaSsaPssPublicKey");
268 key_data_proto.set_value(public_key_proto.SerializeAsString());
269 key_data_proto.set_key_material_type(KeyData::ASYMMETRIC_PUBLIC);
270 return key_data_proto;
271 }
272
EsPublicKeyDataFromKeyStruct(const Struct & key_struct)273 util::StatusOr<KeyData> EsPublicKeyDataFromKeyStruct(const Struct& key_struct) {
274 JwtEcdsaPublicKey public_key_proto;
275 public_key_proto.set_version(0);
276
277 util::StatusOr<std::string> alg = GetStringItem(key_struct, "alg");
278 if (!alg.ok()) {
279 return alg.status();
280 }
281 util::StatusOr<std::string> curve = GetStringItem(key_struct, "crv");
282 if (!curve.ok()) {
283 return curve.status();
284 }
285 if (*alg == "ES256") {
286 if (*curve != "P-256") {
287 return util::Status(absl::StatusCode::kInvalidArgument,
288 "crv is not equal to P-256");
289 }
290 public_key_proto.set_algorithm(JwtEcdsaAlgorithm::ES256);
291 } else if (*alg == "ES384") {
292 if (*curve != "P-384") {
293 return util::Status(absl::StatusCode::kInvalidArgument,
294 "crv is not equal to P-384");
295 }
296 public_key_proto.set_algorithm(JwtEcdsaAlgorithm::ES384);
297 } else if (*alg == "ES512") {
298 if (*curve != "P-521") {
299 return util::Status(absl::StatusCode::kInvalidArgument,
300 "crv is not equal to P-521");
301 }
302 public_key_proto.set_algorithm(JwtEcdsaAlgorithm::ES512);
303 } else {
304 return util::Status(absl::StatusCode::kInvalidArgument, "invalid alg");
305 }
306
307 if (HasItem(key_struct, "d")) {
308 return util::Status(absl::StatusCode::kInvalidArgument,
309 "private keys cannot be converted");
310 }
311 util::Status status_kty = ExpectStringItem(key_struct, "kty", "EC");
312 if (!status_kty.ok()) {
313 return status_kty;
314 }
315 util::Status status_use = ValidateUseIsSig(key_struct);
316 if (!status_use.ok()) {
317 return status_use;
318 }
319 util::Status status_key_ops = ValidateKeyOpsIsVerify(key_struct);
320 if (!status_key_ops.ok()) {
321 return status_key_ops;
322 }
323
324 util::StatusOr<std::string> x = GetStringItem(key_struct, "x");
325 if (!x.ok()) {
326 return x.status();
327 }
328 std::string decoded_x;
329 if (!absl::WebSafeBase64Unescape(*x, &decoded_x)) {
330 return util::Status(absl::StatusCode::kInvalidArgument,
331 "failed to decode x");
332 }
333 public_key_proto.set_x(decoded_x);
334
335 util::StatusOr<std::string> y = GetStringItem(key_struct, "y");
336 if (!y.ok()) {
337 return y.status();
338 }
339 std::string decoded_y;
340 if (!absl::WebSafeBase64Unescape(*y, &decoded_y)) {
341 return util::Status(absl::StatusCode::kInvalidArgument,
342 "failed to decode y");
343 }
344 public_key_proto.set_y(decoded_y);
345
346 if (HasItem(key_struct, "kid")) {
347 util::StatusOr<std::string> kid = GetStringItem(key_struct, "kid");
348 if (!kid.ok()) {
349 return kid.status();
350 }
351 public_key_proto.mutable_custom_kid()->set_value(*kid);
352 }
353 KeyData key_data_proto;
354 key_data_proto.set_type_url(
355 "type.googleapis.com/google.crypto.tink.JwtEcdsaPublicKey");
356 key_data_proto.set_value(public_key_proto.SerializeAsString());
357 key_data_proto.set_key_material_type(KeyData::ASYMMETRIC_PUBLIC);
358 return key_data_proto;
359 }
360
361 } // namespace
362
JwkSetToPublicKeysetHandle(absl::string_view jwk_set)363 util::StatusOr<std::unique_ptr<KeysetHandle>> JwkSetToPublicKeysetHandle(
364 absl::string_view jwk_set) {
365 util::StatusOr<Struct> jwk_set_struct =
366 jwt_internal::JsonStringToProtoStruct(jwk_set);
367 if (!jwk_set_struct.ok()) {
368 return jwk_set_struct.status();
369 }
370 auto it = jwk_set_struct->fields().find("keys");
371 if (it == jwk_set_struct->fields().end()) {
372 return util::Status(absl::StatusCode::kInvalidArgument, "keys not found");
373 }
374 if (it->second.kind_case() != Value::kListValue) {
375 return util::Status(absl::StatusCode::kInvalidArgument,
376 "keys is not a list");
377 }
378 if (it->second.list_value().values_size() <= 0) {
379 return util::Status(absl::StatusCode::kInvalidArgument,
380 "keys list is empty");
381 }
382 uint32_t last_key_id = 0;
383 Keyset keyset;
384 for (const Value& value : it->second.list_value().values()) {
385 if (value.kind_case() != Value::kStructValue) {
386 return util::Status(absl::StatusCode::kInvalidArgument,
387 "key is not a JSON object");
388 }
389 const Struct& key_struct = value.struct_value();
390
391 util::StatusOr<std::string> alg = GetStringItem(key_struct, "alg");
392 if (!alg.ok()) {
393 return alg.status();
394 }
395 absl::string_view alg_prefix = absl::string_view(*alg).substr(0, 2);
396
397 // Add to keyset
398 Keyset_Key* key = keyset.add_key();
399 uint32_t key_id = GenerateUnusedKeyId(keyset);
400 key->set_key_id(key_id);
401 key->set_status(KeyStatusType::ENABLED);
402 key->set_output_prefix_type(OutputPrefixType::RAW);
403
404 if (alg_prefix == "RS") {
405 util::StatusOr<KeyData> key_data =
406 RsPublicKeyDataFromKeyStruct(key_struct);
407 if (!key_data.ok()) {
408 return key_data.status();
409 }
410 *key->mutable_key_data() = *key_data;
411 } else if (alg_prefix == "PS") {
412 util::StatusOr<KeyData> key_data =
413 PsPublicKeyDataFromKeyStruct(key_struct);
414 if (!key_data.ok()) {
415 return key_data.status();
416 }
417 *key->mutable_key_data() = *key_data;
418 } else if (alg_prefix == "ES") {
419 util::StatusOr<KeyData> key_data =
420 EsPublicKeyDataFromKeyStruct(key_struct);
421 if (!key_data.ok()) {
422 return key_data.status();
423 }
424 *key->mutable_key_data() = *key_data;
425 } else {
426 return util::Status(absl::StatusCode::kInvalidArgument,
427 "invalid alg prefix");
428 }
429 last_key_id = key_id;
430 }
431 keyset.set_primary_key_id(last_key_id);
432 return KeysetHandle::ReadNoSecret(keyset.SerializeAsString());
433 }
434
AddStringEntry(Struct * key,absl::string_view name,absl::string_view value)435 void AddStringEntry(Struct* key, absl::string_view name,
436 absl::string_view value) {
437 auto val = key->mutable_fields()->insert({std::string(name), Value()});
438 val.first->second.set_string_value(std::string(value));
439 }
440
AddKeyOpsVerifyEntry(Struct * key)441 void AddKeyOpsVerifyEntry(Struct* key) {
442 auto key_ops = key->mutable_fields()->insert({"key_ops", Value()});
443 key_ops.first->second.mutable_list_value()->add_values()->set_string_value(
444 "verify");
445 }
446
447
EsPublicKeyToKeyStruct(const Keyset_Key & key)448 util::StatusOr<Struct> EsPublicKeyToKeyStruct(const Keyset_Key& key) {
449 JwtEcdsaPublicKey public_key;
450 if (!public_key.ParseFromString(key.key_data().value())) {
451 return util::Status(absl::StatusCode::kInvalidArgument,
452 "parse JwtEcdsaPublicKey failed");
453 }
454
455 Struct output_key;
456
457 switch (public_key.algorithm()) {
458 case JwtEcdsaAlgorithm::ES256:
459 AddStringEntry(&output_key, "crv", "P-256");
460 AddStringEntry(&output_key, "alg", "ES256");
461 break;
462 case JwtEcdsaAlgorithm::ES384:
463 AddStringEntry(&output_key, "crv", "P-384");
464 AddStringEntry(&output_key, "alg", "ES384");
465 break;
466 case JwtEcdsaAlgorithm::ES512:
467 AddStringEntry(&output_key, "crv", "P-521");
468 AddStringEntry(&output_key, "alg", "ES512");
469 break;
470 default:
471 return util::Status(absl::StatusCode::kInvalidArgument,
472 "unknown JwtEcdsaAlgorithm");
473 }
474
475 AddStringEntry(&output_key, "kty", "EC");
476 AddStringEntry(&output_key, "x", absl::WebSafeBase64Escape(public_key.x()));
477 AddStringEntry(&output_key, "y", absl::WebSafeBase64Escape(public_key.y()));
478 AddStringEntry(&output_key, "use", "sig");
479 AddKeyOpsVerifyEntry(&output_key);
480
481 absl::optional<std::string> kid =
482 jwt_internal::GetKid(key.key_id(), key.output_prefix_type());
483 if (kid.has_value()) {
484 AddStringEntry(&output_key, "kid", kid.value());
485 } else if (public_key.has_custom_kid()) {
486 AddStringEntry(&output_key, "kid", public_key.custom_kid().value());
487 }
488 return output_key;
489 }
490
RsPublicKeyToKeyStruct(const Keyset_Key & key)491 util::StatusOr<Struct> RsPublicKeyToKeyStruct(const Keyset_Key& key) {
492 JwtRsaSsaPkcs1PublicKey public_key;
493 if (!public_key.ParseFromString(key.key_data().value())) {
494 return util::Status(absl::StatusCode::kInvalidArgument,
495 "parse JwtRsaSsaPkcs1PublicKey failed");
496 }
497
498 Struct output_key;
499
500 switch (public_key.algorithm()) {
501 case JwtRsaSsaPkcs1Algorithm::RS256:
502 AddStringEntry(&output_key, "alg", "RS256");
503 break;
504 case JwtRsaSsaPkcs1Algorithm::RS384:
505 AddStringEntry(&output_key, "alg", "RS384");
506 break;
507 case JwtRsaSsaPkcs1Algorithm::RS512:
508 AddStringEntry(&output_key, "alg", "RS512");
509 break;
510 default:
511 return util::Status(absl::StatusCode::kInvalidArgument,
512 "unknown JwtRsaSsaPkcs1Algorithm");
513 }
514
515 AddStringEntry(&output_key, "kty", "RSA");
516 AddStringEntry(&output_key, "e", absl::WebSafeBase64Escape(public_key.e()));
517 AddStringEntry(&output_key, "n", absl::WebSafeBase64Escape(public_key.n()));
518 AddStringEntry(&output_key, "use", "sig");
519 AddKeyOpsVerifyEntry(&output_key);
520
521 absl::optional<std::string> kid =
522 jwt_internal::GetKid(key.key_id(), key.output_prefix_type());
523 if (kid.has_value()) {
524 AddStringEntry(&output_key, "kid", kid.value());
525 } else if (public_key.has_custom_kid()) {
526 AddStringEntry(&output_key, "kid", public_key.custom_kid().value());
527 }
528 return output_key;
529 }
530
PsPublicKeyToKeyStruct(const Keyset_Key & key)531 util::StatusOr<Struct> PsPublicKeyToKeyStruct(const Keyset_Key& key) {
532 JwtRsaSsaPssPublicKey public_key;
533 if (!public_key.ParseFromString(key.key_data().value())) {
534 return util::Status(absl::StatusCode::kInvalidArgument,
535 "parse JwtRsaSsaPkcs1PublicKey failed");
536 }
537
538 Struct output_key;
539
540 switch (public_key.algorithm()) {
541 case JwtRsaSsaPssAlgorithm::PS256:
542 AddStringEntry(&output_key, "alg", "PS256");
543 break;
544 case JwtRsaSsaPssAlgorithm::PS384:
545 AddStringEntry(&output_key, "alg", "PS384");
546 break;
547 case JwtRsaSsaPssAlgorithm::PS512:
548 AddStringEntry(&output_key, "alg", "PS512");
549 break;
550 default:
551 return util::Status(absl::StatusCode::kInvalidArgument,
552 "unknown JwtRsaSsaPkcs1Algorithm");
553 }
554
555 AddStringEntry(&output_key, "kty", "RSA");
556 AddStringEntry(&output_key, "e", absl::WebSafeBase64Escape(public_key.e()));
557 AddStringEntry(&output_key, "n", absl::WebSafeBase64Escape(public_key.n()));
558 AddStringEntry(&output_key, "use", "sig");
559 AddKeyOpsVerifyEntry(&output_key);
560
561 absl::optional<std::string> kid =
562 jwt_internal::GetKid(key.key_id(), key.output_prefix_type());
563 if (kid.has_value()) {
564 AddStringEntry(&output_key, "kid", kid.value());
565 } else if (public_key.has_custom_kid()) {
566 AddStringEntry(&output_key, "kid", public_key.custom_kid().value());
567 }
568 return output_key;
569 }
570
JwkSetFromPublicKeysetHandle(const KeysetHandle & keyset_handle)571 util::StatusOr<std::string> JwkSetFromPublicKeysetHandle(
572 const KeysetHandle& keyset_handle) {
573 std::stringbuf keyset_buf;
574 util::StatusOr<std::unique_ptr<BinaryKeysetWriter>> writer =
575 BinaryKeysetWriter::New(absl::make_unique<std::ostream>(&keyset_buf));
576 if (!writer.ok()) {
577 return writer.status();
578 }
579 util::Status status = keyset_handle.WriteNoSecret((*writer).get());
580 if (!status.ok()) {
581 return status;
582 }
583 Keyset keyset;
584 if (!keyset.ParseFromString(keyset_buf.str())) {
585 return util::Status(absl::StatusCode::kInvalidArgument,
586 "parse Keyset failed");
587 }
588
589 Struct output;
590 auto insertion_result = output.mutable_fields()->insert({"keys", Value()});
591 ListValue* keys_list = insertion_result.first->second.mutable_list_value();
592
593 for (const Keyset::Key& key : keyset.key()) {
594 if (key.status() != KeyStatusType::ENABLED) {
595 continue;
596 }
597 if ((key.output_prefix_type() != OutputPrefixType::RAW) &&
598 (key.output_prefix_type() != OutputPrefixType::TINK)) {
599 return util::Status(absl::StatusCode::kInvalidArgument,
600 "Unknown output prefix type");
601 }
602
603 if (key.key_data().key_material_type() != KeyData::ASYMMETRIC_PUBLIC) {
604 return util::Status(absl::StatusCode::kInvalidArgument,
605 "Only asymmetric public keys are supported");
606 }
607 if (key.key_data().type_url() ==
608 "type.googleapis.com/google.crypto.tink.JwtEcdsaPublicKey") {
609 util::StatusOr<Struct> output_key = EsPublicKeyToKeyStruct(key);
610 if (!output_key.ok()) {
611 return output_key.status();
612 }
613 *keys_list->add_values()->mutable_struct_value() = *output_key;
614 } else if (key.key_data().type_url() ==
615 "type.googleapis.com/"
616 "google.crypto.tink.JwtRsaSsaPkcs1PublicKey") {
617 util::StatusOr<Struct> output_key = RsPublicKeyToKeyStruct(key);
618 if (!output_key.ok()) {
619 return output_key.status();
620 }
621 *keys_list->add_values()->mutable_struct_value() = *output_key;
622 } else if (key.key_data().type_url() ==
623 "type.googleapis.com/"
624 "google.crypto.tink.JwtRsaSsaPssPublicKey") {
625 util::StatusOr<Struct> output_key = PsPublicKeyToKeyStruct(key);
626 if (!output_key.ok()) {
627 return output_key.status();
628 }
629 *keys_list->add_values()->mutable_struct_value() = *output_key;
630 } else {
631 return util::Status(absl::StatusCode::kInvalidArgument,
632 "Unknown key type url");
633 }
634 }
635 return jwt_internal::ProtoStructToJsonString(output);
636 }
637
638 } // namespace tink
639 } // namespace crypto
640