xref: /aosp_15_r20/external/tink/cc/jwt/jwk_set_converter.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
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