Coverage Report

Created: 2026-08-13 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/proc/self/cwd/src/jwks.cc
Line
Count
Source
1
// Copyright 2018 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
//    https://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
#include "jwt_verify_lib/jwks.h"
16
17
#include <assert.h>
18
19
#include <iostream>
20
21
#include "absl/strings/escaping.h"
22
#include "absl/strings/match.h"
23
#include "google/protobuf/struct.pb.h"
24
#include "google/protobuf/util/json_util.h"
25
#include "jwt_verify_lib/struct_utils.h"
26
#include "openssl/bio.h"
27
#include "openssl/bn.h"
28
#include "openssl/curve25519.h"
29
#include "openssl/ecdsa.h"
30
#include "openssl/evp.h"
31
#include "openssl/rsa.h"
32
#include "openssl/sha.h"
33
34
namespace google {
35
namespace jwt_verify {
36
37
namespace {
38
39
// The x509 certificate prefix string
40
const char kX509CertPrefix[] = "-----BEGIN CERTIFICATE-----\n";
41
// The x509 certificate suffix string
42
const char kX509CertSuffix[] = "\n-----END CERTIFICATE-----\n";
43
44
// A convinence inline cast function.
45
84.4k
inline const uint8_t* castToUChar(const std::string& str) {
46
84.4k
  return reinterpret_cast<const uint8_t*>(str.c_str());
47
84.4k
}
48
49
/** Class to create key object from string of public key, formatted in PEM
50
 * or JWKs.
51
 * If it fails, status_ holds the failure reason.
52
 *
53
 * Usage example:
54
 * KeyGetter e;
55
 * bssl::UniquePtr<EVP_PKEY> pkey = e.createEcKeyFromJwkEC(...);
56
 */
57
class KeyGetter : public WithStatus {
58
 public:
59
9.72k
  bssl::UniquePtr<EVP_PKEY> createEvpPkeyFromPem(const std::string& pkey_pem) {
60
9.72k
    bssl::UniquePtr<BIO> buf(BIO_new_mem_buf(pkey_pem.data(), pkey_pem.size()));
61
9.72k
    if (buf == nullptr) {
62
0
      updateStatus(Status::JwksBioAllocError);
63
0
      return nullptr;
64
0
    }
65
9.72k
    bssl::UniquePtr<EVP_PKEY> key(
66
9.72k
        PEM_read_bio_PUBKEY(buf.get(), nullptr, nullptr, nullptr));
67
9.72k
    if (key == nullptr) {
68
9.68k
      updateStatus(Status::JwksPemBadBase64);
69
9.68k
      return nullptr;
70
9.68k
    }
71
46
    return key;
72
9.72k
  }
73
74
  bssl::UniquePtr<EC_KEY> createEcKeyFromJwkEC(int nid, const std::string& x,
75
18.6k
                                               const std::string& y) {
76
18.6k
    bssl::UniquePtr<EC_KEY> ec_key(EC_KEY_new_by_curve_name(nid));
77
18.6k
    if (!ec_key) {
78
0
      updateStatus(Status::JwksEcCreateKeyFail);
79
0
      return nullptr;
80
0
    }
81
18.6k
    bssl::UniquePtr<BIGNUM> bn_x = createBigNumFromBase64UrlString(x);
82
18.6k
    bssl::UniquePtr<BIGNUM> bn_y = createBigNumFromBase64UrlString(y);
83
18.6k
    if (!bn_x || !bn_y) {
84
      // EC public key field x or y Base64 decode fail
85
2.60k
      updateStatus(Status::JwksEcXorYBadBase64);
86
2.60k
      return nullptr;
87
2.60k
    }
88
89
16.0k
    if (EC_KEY_set_public_key_affine_coordinates(ec_key.get(), bn_x.get(),
90
16.0k
                                                 bn_y.get()) == 0) {
91
4.91k
      updateStatus(Status::JwksEcParseError);
92
4.91k
      return nullptr;
93
4.91k
    }
94
11.1k
    return ec_key;
95
16.0k
  }
96
97
  bssl::UniquePtr<RSA> createRsaFromJwk(const std::string& n,
98
27.1k
                                        const std::string& e) {
99
27.1k
    bssl::UniquePtr<BIGNUM> n_bn = createBigNumFromBase64UrlString(n);
100
27.1k
    bssl::UniquePtr<BIGNUM> e_bn = createBigNumFromBase64UrlString(e);
101
27.1k
    if (n_bn == nullptr || e_bn == nullptr) {
102
      // RSA public key field is missing or has parse error.
103
3.92k
      updateStatus(Status::JwksRsaParseError);
104
3.92k
      return nullptr;
105
3.92k
    }
106
23.2k
    if (BN_cmp_word(e_bn.get(), 3) != 0 &&
107
9.74k
        BN_cmp_word(e_bn.get(), 65537) != 0) {
108
      // non-standard key; reject it early.
109
487
      updateStatus(Status::JwksRsaParseError);
110
487
      return nullptr;
111
487
    }
112
    // When jwt_verify_lib's minimum supported BoringSSL revision is past
113
    // https://boringssl-review.googlesource.com/c/boringssl/+/59386 (May 2023),
114
    // replace all this with `RSA_new_public_key` instead.
115
22.7k
    bssl::UniquePtr<RSA> rsa(RSA_new());
116
22.7k
    if (rsa == nullptr ||
117
22.7k
        !RSA_set0_key(rsa.get(), n_bn.get(), e_bn.get(), /*d=*/nullptr)) {
118
      // Allocation or programmer error.
119
0
      updateStatus(Status::JwksRsaParseError);
120
0
      return nullptr;
121
0
    }
122
    // `RSA_set0_key` takes ownership, but only on success.
123
22.7k
    n_bn.release();
124
22.7k
    e_bn.release();
125
22.7k
    if (!RSA_check_key(rsa.get())) {
126
      // Not a valid RSA public key.
127
2.93k
      updateStatus(Status::JwksRsaParseError);
128
2.93k
      return nullptr;
129
2.93k
    }
130
19.8k
    return rsa;
131
22.7k
  }
132
133
  std::string createRawKeyFromJwkOKP(int nid, size_t keylen,
134
11.5k
                                     const std::string& x) {
135
11.5k
    std::string x_decoded;
136
11.5k
    if (!absl::WebSafeBase64Unescape(x, &x_decoded)) {
137
1.08k
      updateStatus(Status::JwksOKPXBadBase64);
138
10.5k
    } else if (x_decoded.length() != keylen) {
139
1.52k
      updateStatus(Status::JwksOKPXWrongLength);
140
1.52k
    }
141
    // For OKP the "x" value is the public key and can just be used as-is
142
11.5k
    return x_decoded;
143
11.5k
  }
144
145
 private:
146
  bssl::UniquePtr<BIGNUM> createBigNumFromBase64UrlString(
147
91.7k
      const std::string& s) {
148
91.7k
    std::string s_decoded;
149
91.7k
    if (!absl::WebSafeBase64Unescape(s, &s_decoded)) {
150
7.30k
      return nullptr;
151
7.30k
    }
152
84.4k
    return bssl::UniquePtr<BIGNUM>(
153
84.4k
        BN_bin2bn(castToUChar(s_decoded), s_decoded.length(), NULL));
154
91.7k
  };
155
};
156
157
Status extractJwkFromJwkRSA(const ::google::protobuf::Struct& jwk_pb,
158
31.8k
                            Jwks::Pubkey* jwk) {
159
31.8k
  if (!jwk->alg_.empty() &&
160
2.93k
      (jwk->alg_.size() < 2 || (jwk->alg_.compare(0, 2, "RS") != 0 &&
161
1.53k
                                jwk->alg_.compare(0, 2, "PS") != 0))) {
162
1.01k
    return Status::JwksRSAKeyBadAlg;
163
1.01k
  }
164
165
30.8k
  StructUtils jwk_getter(jwk_pb);
166
30.8k
  std::string n_str;
167
30.8k
  auto code = jwk_getter.GetString("n", &n_str);
168
30.8k
  if (code == StructUtils::MISSING) {
169
2.26k
    return Status::JwksRSAKeyMissingN;
170
2.26k
  }
171
28.5k
  if (code == StructUtils::WRONG_TYPE) {
172
66
    return Status::JwksRSAKeyBadN;
173
66
  }
174
175
28.4k
  std::string e_str;
176
28.4k
  code = jwk_getter.GetString("e", &e_str);
177
28.4k
  if (code == StructUtils::MISSING) {
178
956
    return Status::JwksRSAKeyMissingE;
179
956
  }
180
27.5k
  if (code == StructUtils::WRONG_TYPE) {
181
326
    return Status::JwksRSAKeyBadE;
182
326
  }
183
184
27.1k
  KeyGetter e;
185
27.1k
  jwk->rsa_ = e.createRsaFromJwk(n_str, e_str);
186
27.1k
  return e.getStatus();
187
27.5k
}
188
189
Status extractJwkFromJwkEC(const ::google::protobuf::Struct& jwk_pb,
190
37.1k
                           Jwks::Pubkey* jwk) {
191
37.1k
  if (!jwk->alg_.empty() &&
192
14.8k
      (jwk->alg_.size() < 2 || jwk->alg_.compare(0, 2, "ES") != 0)) {
193
1.54k
    return Status::JwksECKeyBadAlg;
194
1.54k
  }
195
196
35.5k
  StructUtils jwk_getter(jwk_pb);
197
35.5k
  std::string crv_str;
198
35.5k
  auto code = jwk_getter.GetString("crv", &crv_str);
199
35.5k
  if (code == StructUtils::MISSING) {
200
13.4k
    crv_str = "";
201
13.4k
  }
202
35.5k
  if (code == StructUtils::WRONG_TYPE) {
203
1.39k
    return Status::JwksECKeyBadCrv;
204
1.39k
  }
205
34.1k
  jwk->crv_ = crv_str;
206
207
  // If both alg and crv specified, make sure they match
208
34.1k
  if (!jwk->alg_.empty() && !jwk->crv_.empty()) {
209
11.1k
    if (!((jwk->alg_ == "ES256" && jwk->crv_ == "P-256") ||
210
8.57k
          (jwk->alg_ == "ES384" && jwk->crv_ == "P-384") ||
211
6.49k
          (jwk->alg_ == "ES512" && jwk->crv_ == "P-521"))) {
212
5.94k
      return Status::JwksECKeyAlgNotCompatibleWithCrv;
213
5.94k
    }
214
11.1k
  }
215
216
  // If neither alg or crv is set, assume P-256
217
28.2k
  if (jwk->alg_.empty() && jwk->crv_.empty()) {
218
11.3k
    jwk->crv_ = "P-256";
219
11.3k
  }
220
221
28.2k
  int nid;
222
28.2k
  if (jwk->alg_ == "ES256" || jwk->crv_ == "P-256") {
223
15.2k
    nid = NID_X9_62_prime256v1;
224
15.2k
    jwk->crv_ = "P-256";
225
15.2k
  } else if (jwk->alg_ == "ES384" || jwk->crv_ == "P-384") {
226
5.75k
    nid = NID_secp384r1;
227
5.75k
    jwk->crv_ = "P-384";
228
7.27k
  } else if (jwk->alg_ == "ES512" || jwk->crv_ == "P-521") {
229
3.68k
    nid = NID_secp521r1;
230
3.68k
    jwk->crv_ = "P-521";
231
3.68k
  } else {
232
3.58k
    return Status::JwksECKeyAlgOrCrvUnsupported;
233
3.58k
  }
234
235
24.6k
  std::string x_str;
236
24.6k
  code = jwk_getter.GetString("x", &x_str);
237
24.6k
  if (code == StructUtils::MISSING) {
238
3.76k
    return Status::JwksECKeyMissingX;
239
3.76k
  }
240
20.9k
  if (code == StructUtils::WRONG_TYPE) {
241
340
    return Status::JwksECKeyBadX;
242
340
  }
243
244
20.5k
  std::string y_str;
245
20.5k
  code = jwk_getter.GetString("y", &y_str);
246
20.5k
  if (code == StructUtils::MISSING) {
247
1.69k
    return Status::JwksECKeyMissingY;
248
1.69k
  }
249
18.8k
  if (code == StructUtils::WRONG_TYPE) {
250
214
    return Status::JwksECKeyBadY;
251
214
  }
252
253
18.6k
  KeyGetter e;
254
18.6k
  jwk->ec_key_ = e.createEcKeyFromJwkEC(nid, x_str, y_str);
255
18.6k
  return e.getStatus();
256
18.8k
}
257
258
Status extractJwkFromJwkOct(const ::google::protobuf::Struct& jwk_pb,
259
33.9k
                            Jwks::Pubkey* jwk) {
260
33.9k
  if (!jwk->alg_.empty() && jwk->alg_ != "HS256" && jwk->alg_ != "HS384" &&
261
1.41k
      jwk->alg_ != "HS512") {
262
610
    return Status::JwksHMACKeyBadAlg;
263
610
  }
264
265
33.3k
  StructUtils jwk_getter(jwk_pb);
266
33.3k
  std::string k_str;
267
33.3k
  auto code = jwk_getter.GetString("k", &k_str);
268
33.3k
  if (code == StructUtils::MISSING) {
269
361
    return Status::JwksHMACKeyMissingK;
270
361
  }
271
33.0k
  if (code == StructUtils::WRONG_TYPE) {
272
74
    return Status::JwksHMACKeyBadK;
273
74
  }
274
275
32.9k
  std::string key;
276
32.9k
  if (!absl::WebSafeBase64Unescape(k_str, &key) || key.empty()) {
277
10.1k
    return Status::JwksOctBadBase64;
278
10.1k
  }
279
280
22.7k
  jwk->hmac_key_ = key;
281
22.7k
  return Status::Ok;
282
32.9k
}
283
284
// The "OKP" key type is defined in https://tools.ietf.org/html/rfc8037
285
Status extractJwkFromJwkOKP(const ::google::protobuf::Struct& jwk_pb,
286
15.7k
                            Jwks::Pubkey* jwk) {
287
  // alg is not required, but if present it must be EdDSA
288
15.7k
  if (!jwk->alg_.empty() && jwk->alg_ != "EdDSA") {
289
909
    return Status::JwksOKPKeyBadAlg;
290
909
  }
291
292
  // crv is required per https://tools.ietf.org/html/rfc8037#section-2
293
14.8k
  StructUtils jwk_getter(jwk_pb);
294
14.8k
  std::string crv_str;
295
14.8k
  auto code = jwk_getter.GetString("crv", &crv_str);
296
14.8k
  if (code == StructUtils::MISSING) {
297
635
    return Status::JwksOKPKeyMissingCrv;
298
635
  }
299
14.1k
  if (code == StructUtils::WRONG_TYPE) {
300
220
    return Status::JwksOKPKeyBadCrv;
301
220
  }
302
13.9k
  jwk->crv_ = crv_str;
303
304
  // Valid crv values:
305
  // https://tools.ietf.org/html/rfc8037#section-3
306
  // https://www.iana.org/assignments/jose/jose.xhtml#web-key-elliptic-curve
307
  // In addition to Ed25519 there are:
308
  // X25519: Implemented in boringssl but not used for JWT and thus not
309
  // supported here
310
  // Ed448 and X448: Not implemented in boringssl
311
13.9k
  int nid;
312
13.9k
  size_t keylen;
313
13.9k
  if (jwk->crv_ == "Ed25519") {
314
12.0k
    nid = EVP_PKEY_ED25519;
315
12.0k
    keylen = ED25519_PUBLIC_KEY_LEN;
316
12.0k
  } else {
317
1.92k
    return Status::JwksOKPKeyCrvUnsupported;
318
1.92k
  }
319
320
  // x is required per https://tools.ietf.org/html/rfc8037#section-2
321
12.0k
  std::string x_str;
322
12.0k
  code = jwk_getter.GetString("x", &x_str);
323
12.0k
  if (code == StructUtils::MISSING) {
324
227
    return Status::JwksOKPKeyMissingX;
325
227
  }
326
11.7k
  if (code == StructUtils::WRONG_TYPE) {
327
194
    return Status::JwksOKPKeyBadX;
328
194
  }
329
330
11.5k
  KeyGetter e;
331
11.5k
  jwk->okp_key_raw_ = e.createRawKeyFromJwkOKP(nid, keylen, x_str);
332
11.5k
  return e.getStatus();
333
11.7k
}
334
335
158k
Status extractJwk(const ::google::protobuf::Struct& jwk_pb, Jwks::Pubkey* jwk) {
336
158k
  StructUtils jwk_getter(jwk_pb);
337
  // Check "kty" parameter, it should exist.
338
  // https://tools.ietf.org/html/rfc7517#section-4.1
339
158k
  auto code = jwk_getter.GetString("kty", &jwk->kty_);
340
158k
  if (code == StructUtils::MISSING) {
341
18.7k
    return Status::JwksMissingKty;
342
18.7k
  }
343
139k
  if (code == StructUtils::WRONG_TYPE) {
344
979
    return Status::JwksBadKty;
345
979
  }
346
347
  // "kid" and "alg" are optional, if they do not exist, set them to
348
  // empty. https://tools.ietf.org/html/rfc7517#page-8
349
138k
  jwk_getter.GetString("kid", &jwk->kid_);
350
138k
  jwk_getter.GetString("alg", &jwk->alg_);
351
352
  // Extract public key according to "kty" value.
353
  // https://tools.ietf.org/html/rfc7518#section-6.1
354
138k
  if (jwk->kty_ == "EC") {
355
37.1k
    return extractJwkFromJwkEC(jwk_pb, jwk);
356
101k
  } else if (jwk->kty_ == "RSA") {
357
31.8k
    return extractJwkFromJwkRSA(jwk_pb, jwk);
358
69.4k
  } else if (jwk->kty_ == "oct") {
359
33.9k
    return extractJwkFromJwkOct(jwk_pb, jwk);
360
35.4k
  } else if (jwk->kty_ == "OKP") {
361
15.7k
    return extractJwkFromJwkOKP(jwk_pb, jwk);
362
15.7k
  }
363
19.7k
  return Status::JwksNotImplementedKty;
364
138k
}
365
366
1.66k
Status extractX509(const std::string& key, Jwks::Pubkey* jwk) {
367
1.66k
  jwk->bio_.reset(BIO_new(BIO_s_mem()));
368
1.66k
  if (BIO_write(jwk->bio_.get(), key.c_str(), key.length()) <= 0) {
369
0
    return Status::JwksX509BioWriteError;
370
0
  }
371
1.66k
  jwk->x509_.reset(
372
1.66k
      PEM_read_bio_X509(jwk->bio_.get(), nullptr, nullptr, nullptr));
373
1.66k
  if (jwk->x509_ == nullptr) {
374
1.06k
    return Status::JwksX509ParseError;
375
1.06k
  }
376
597
  bssl::UniquePtr<EVP_PKEY> tmp_pkey(X509_get_pubkey(jwk->x509_.get()));
377
597
  if (tmp_pkey == nullptr) {
378
18
    return Status::JwksX509GetPubkeyError;
379
18
  }
380
579
  jwk->rsa_.reset(EVP_PKEY_get1_RSA(tmp_pkey.get()));
381
579
  if (jwk->rsa_ == nullptr) {
382
0
    return Status::JwksX509GetPubkeyError;
383
0
  }
384
579
  return Status::Ok;
385
579
}
386
387
1.63k
bool shouldCheckX509(const ::google::protobuf::Struct& jwks_pb) {
388
1.63k
  if (jwks_pb.fields().empty()) {
389
5
    return false;
390
5
  }
391
392
2.77k
  for (const auto& kid : jwks_pb.fields()) {
393
2.77k
    if (kid.first.empty() ||
394
2.76k
        kid.second.kind_case() != google::protobuf::Value::kStringValue) {
395
379
      return false;
396
379
    }
397
2.39k
    const std::string& cert = kid.second.string_value();
398
2.39k
    if (!absl::StartsWith(cert, kX509CertPrefix) ||
399
2.29k
        !absl::EndsWith(cert, kX509CertSuffix)) {
400
125
      return false;
401
125
    }
402
2.39k
  }
403
1.13k
  return true;
404
1.63k
}
405
406
Status createFromX509(const ::google::protobuf::Struct& jwks_pb,
407
1.13k
                      std::vector<Jwks::PubkeyPtr>& keys) {
408
1.66k
  for (const auto& kid : jwks_pb.fields()) {
409
1.66k
    Jwks::PubkeyPtr key_ptr(new Jwks::Pubkey());
410
1.66k
    Status status = extractX509(kid.second.string_value(), key_ptr.get());
411
1.66k
    if (status != Status::Ok) {
412
1.08k
      return status;
413
1.08k
    }
414
415
579
    key_ptr->kid_ = kid.first;
416
579
    key_ptr->kty_ = "RSA";
417
579
    keys.push_back(std::move(key_ptr));
418
579
  }
419
47
  return Status::Ok;
420
1.13k
}
421
422
}  // namespace
423
424
Status Jwks::addKeyFromPem(const std::string& pkey, const std::string& kid,
425
0
                           const std::string& alg) {
426
0
  JwksPtr tmp = Jwks::createFromPem(pkey, kid, alg);
427
0
  if (tmp->getStatus() != Status::Ok) {
428
0
    return tmp->getStatus();
429
0
  }
430
0
  keys_.insert(keys_.end(), std::make_move_iterator(tmp->keys_.begin()),
431
0
               std::make_move_iterator(tmp->keys_.end()));
432
0
  return Status::Ok;
433
0
}
434
435
19.4k
JwksPtr Jwks::createFrom(const std::string& pkey, Type type) {
436
19.4k
  JwksPtr keys(new Jwks());
437
19.4k
  switch (type) {
438
9.72k
    case Type::JWKS:
439
9.72k
      keys->createFromJwksCore(pkey);
440
9.72k
      break;
441
9.72k
    case Type::PEM:
442
9.72k
      keys->createFromPemCore(pkey);
443
9.72k
      break;
444
19.4k
  }
445
19.4k
  return keys;
446
19.4k
}
447
448
JwksPtr Jwks::createFromPem(const std::string& pkey, const std::string& kid,
449
0
                            const std::string& alg) {
450
0
  std::unique_ptr<Jwks> ret = Jwks::createFrom(pkey, Jwks::PEM);
451
0
  if (ret->getStatus() != Status::Ok) {
452
0
    return ret;
453
0
  }
454
0
  if (ret->keys_.size() != 1) {
455
0
    ret->updateStatus(Status::JwksPemBadBase64);
456
0
    return ret;
457
0
  }
458
0
  Pubkey* jwk = ret->keys_.at(0).get();
459
0
  jwk->kid_ = kid;
460
0
  jwk->alg_ = alg;
461
462
  // If alg is a known EC algorithm, set the correct crv as well.
463
0
  if (jwk->alg_ == "ES256") {
464
0
    jwk->crv_ = "P-256";
465
0
  }
466
0
  if (jwk->alg_ == "ES384") {
467
0
    jwk->crv_ = "P-384";
468
0
  }
469
0
  if (jwk->alg_ == "ES512") {
470
0
    jwk->crv_ = "P-521";
471
0
  }
472
0
  return ret;
473
0
}
474
475
// pkey_pem must be a PEM-encoded PKCS #8 public key.
476
// This is the format that starts with -----BEGIN PUBLIC KEY-----.
477
9.72k
void Jwks::createFromPemCore(const std::string& pkey_pem) {
478
9.72k
  keys_.clear();
479
9.72k
  PubkeyPtr key_ptr(new Pubkey());
480
9.72k
  KeyGetter e;
481
9.72k
  bssl::UniquePtr<EVP_PKEY> evp_pkey(e.createEvpPkeyFromPem(pkey_pem));
482
9.72k
  updateStatus(e.getStatus());
483
484
9.72k
  if (evp_pkey == nullptr) {
485
9.68k
    assert(e.getStatus() != Status::Ok);
486
9.68k
    return;
487
9.68k
  }
488
9.72k
  assert(e.getStatus() == Status::Ok);
489
490
46
  switch (EVP_PKEY_id(evp_pkey.get())) {
491
22
    case EVP_PKEY_RSA:
492
22
      key_ptr->rsa_.reset(EVP_PKEY_get1_RSA(evp_pkey.get()));
493
22
      key_ptr->kty_ = "RSA";
494
22
      break;
495
24
    case EVP_PKEY_EC:
496
24
      key_ptr->ec_key_.reset(EVP_PKEY_get1_EC_KEY(evp_pkey.get()));
497
24
      key_ptr->kty_ = "EC";
498
24
      break;
499
0
#ifndef BORINGSSL_FIPS
500
0
    case EVP_PKEY_ED25519: {
501
0
      uint8_t raw_key[ED25519_PUBLIC_KEY_LEN];
502
0
      size_t out_len = ED25519_PUBLIC_KEY_LEN;
503
0
      if (EVP_PKEY_get_raw_public_key(evp_pkey.get(), raw_key, &out_len) != 1 ||
504
0
          out_len != ED25519_PUBLIC_KEY_LEN) {
505
0
        updateStatus(Status::JwksPemGetRawEd25519Error);
506
0
        return;
507
0
      }
508
0
      key_ptr->okp_key_raw_ =
509
0
          std::string(reinterpret_cast<const char*>(raw_key), out_len);
510
0
      key_ptr->kty_ = "OKP";
511
0
      key_ptr->crv_ = "Ed25519";
512
0
      break;
513
0
    }
514
0
#endif
515
0
    default:
516
0
      updateStatus(Status::JwksPemNotImplementedKty);
517
0
      return;
518
46
  }
519
520
46
  keys_.push_back(std::move(key_ptr));
521
46
}
522
523
9.72k
void Jwks::createFromJwksCore(const std::string& jwks_json) {
524
9.72k
  keys_.clear();
525
526
9.72k
  ::google::protobuf::util::JsonParseOptions options;
527
9.72k
  ::google::protobuf::Struct jwks_pb;
528
9.72k
  const auto status = ::google::protobuf::util::JsonStringToMessage(
529
9.72k
      jwks_json, &jwks_pb, options);
530
9.72k
  if (!status.ok()) {
531
4.12k
    updateStatus(Status::JwksParseError);
532
4.12k
    return;
533
4.12k
  }
534
535
5.60k
  const auto& fields = jwks_pb.fields();
536
5.60k
  const auto keys_it = fields.find("keys");
537
5.60k
  if (keys_it == fields.end()) {
538
    // X509 doesn't have "keys" field.
539
1.63k
    if (shouldCheckX509(jwks_pb)) {
540
1.13k
      updateStatus(createFromX509(jwks_pb, keys_));
541
1.13k
      return;
542
1.13k
    }
543
509
    updateStatus(Status::JwksNoKeys);
544
509
    return;
545
1.63k
  }
546
3.96k
  if (keys_it->second.kind_case() != google::protobuf::Value::kListValue) {
547
2
    updateStatus(Status::JwksBadKeys);
548
2
    return;
549
2
  }
550
551
262k
  for (const auto& key_value : keys_it->second.list_value().values()) {
552
262k
    if (key_value.kind_case() != ::google::protobuf::Value::kStructValue) {
553
104k
      continue;
554
104k
    }
555
158k
    PubkeyPtr key_ptr(new Pubkey());
556
158k
    Status status = extractJwk(key_value.struct_value(), key_ptr.get());
557
158k
    if (status == Status::Ok) {
558
62.7k
      keys_.push_back(std::move(key_ptr));
559
62.7k
      resetStatus(status);
560
95.3k
    } else {
561
95.3k
      updateStatus(status);
562
95.3k
    }
563
158k
  }
564
565
3.96k
  if (keys_.empty()) {
566
1.14k
    updateStatus(Status::JwksNoValidKeys);
567
2.82k
  } else {
568
2.82k
    resetStatus(Status::Ok);
569
2.82k
  }
570
3.96k
}
571
572
}  // namespace jwt_verify
573
}  // namespace google