Coverage Report

Created: 2026-08-14 06:53

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
79.9k
inline const uint8_t* castToUChar(const std::string& str) {
46
79.9k
  return reinterpret_cast<const uint8_t*>(str.c_str());
47
79.9k
}
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.32k
  bssl::UniquePtr<EVP_PKEY> createEvpPkeyFromPem(const std::string& pkey_pem) {
60
9.32k
    bssl::UniquePtr<BIO> buf(BIO_new_mem_buf(pkey_pem.data(), pkey_pem.size()));
61
9.32k
    if (buf == nullptr) {
62
0
      updateStatus(Status::JwksBioAllocError);
63
0
      return nullptr;
64
0
    }
65
9.32k
    bssl::UniquePtr<EVP_PKEY> key(
66
9.32k
        PEM_read_bio_PUBKEY(buf.get(), nullptr, nullptr, nullptr));
67
9.32k
    if (key == nullptr) {
68
9.28k
      updateStatus(Status::JwksPemBadBase64);
69
9.28k
      return nullptr;
70
9.28k
    }
71
41
    return key;
72
9.32k
  }
73
74
  bssl::UniquePtr<EC_KEY> createEcKeyFromJwkEC(int nid, const std::string& x,
75
17.2k
                                               const std::string& y) {
76
17.2k
    bssl::UniquePtr<EC_KEY> ec_key(EC_KEY_new_by_curve_name(nid));
77
17.2k
    if (!ec_key) {
78
0
      updateStatus(Status::JwksEcCreateKeyFail);
79
0
      return nullptr;
80
0
    }
81
17.2k
    bssl::UniquePtr<BIGNUM> bn_x = createBigNumFromBase64UrlString(x);
82
17.2k
    bssl::UniquePtr<BIGNUM> bn_y = createBigNumFromBase64UrlString(y);
83
17.2k
    if (!bn_x || !bn_y) {
84
      // EC public key field x or y Base64 decode fail
85
2.50k
      updateStatus(Status::JwksEcXorYBadBase64);
86
2.50k
      return nullptr;
87
2.50k
    }
88
89
14.7k
    if (EC_KEY_set_public_key_affine_coordinates(ec_key.get(), bn_x.get(),
90
14.7k
                                                 bn_y.get()) == 0) {
91
4.41k
      updateStatus(Status::JwksEcParseError);
92
4.41k
      return nullptr;
93
4.41k
    }
94
10.3k
    return ec_key;
95
14.7k
  }
96
97
  bssl::UniquePtr<RSA> createRsaFromJwk(const std::string& n,
98
26.0k
                                        const std::string& e) {
99
26.0k
    bssl::UniquePtr<BIGNUM> n_bn = createBigNumFromBase64UrlString(n);
100
26.0k
    bssl::UniquePtr<BIGNUM> e_bn = createBigNumFromBase64UrlString(e);
101
26.0k
    if (n_bn == nullptr || e_bn == nullptr) {
102
      // RSA public key field is missing or has parse error.
103
3.53k
      updateStatus(Status::JwksRsaParseError);
104
3.53k
      return nullptr;
105
3.53k
    }
106
22.5k
    if (BN_cmp_word(e_bn.get(), 3) != 0 &&
107
9.71k
        BN_cmp_word(e_bn.get(), 65537) != 0) {
108
      // non-standard key; reject it early.
109
423
      updateStatus(Status::JwksRsaParseError);
110
423
      return nullptr;
111
423
    }
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.1k
    bssl::UniquePtr<RSA> rsa(RSA_new());
116
22.1k
    if (rsa == nullptr ||
117
22.1k
        !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.1k
    n_bn.release();
124
22.1k
    e_bn.release();
125
22.1k
    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.1k
    return rsa;
131
22.1k
  }
132
133
  std::string createRawKeyFromJwkOKP(int nid, size_t keylen,
134
10.9k
                                     const std::string& x) {
135
10.9k
    std::string x_decoded;
136
10.9k
    if (!absl::WebSafeBase64Unescape(x, &x_decoded)) {
137
1.08k
      updateStatus(Status::JwksOKPXBadBase64);
138
9.89k
    } else if (x_decoded.length() != keylen) {
139
1.34k
      updateStatus(Status::JwksOKPXWrongLength);
140
1.34k
    }
141
    // For OKP the "x" value is the public key and can just be used as-is
142
10.9k
    return x_decoded;
143
10.9k
  }
144
145
 private:
146
  bssl::UniquePtr<BIGNUM> createBigNumFromBase64UrlString(
147
86.6k
      const std::string& s) {
148
86.6k
    std::string s_decoded;
149
86.6k
    if (!absl::WebSafeBase64Unescape(s, &s_decoded)) {
150
6.63k
      return nullptr;
151
6.63k
    }
152
79.9k
    return bssl::UniquePtr<BIGNUM>(
153
79.9k
        BN_bin2bn(castToUChar(s_decoded), s_decoded.length(), NULL));
154
86.6k
  };
155
};
156
157
Status extractJwkFromJwkRSA(const ::google::protobuf::Struct& jwk_pb,
158
30.8k
                            Jwks::Pubkey* jwk) {
159
30.8k
  if (!jwk->alg_.empty() &&
160
3.47k
      (jwk->alg_.size() < 2 || (jwk->alg_.compare(0, 2, "RS") != 0 &&
161
1.73k
                                jwk->alg_.compare(0, 2, "PS") != 0))) {
162
1.16k
    return Status::JwksRSAKeyBadAlg;
163
1.16k
  }
164
165
29.7k
  StructUtils jwk_getter(jwk_pb);
166
29.7k
  std::string n_str;
167
29.7k
  auto code = jwk_getter.GetString("n", &n_str);
168
29.7k
  if (code == StructUtils::MISSING) {
169
2.33k
    return Status::JwksRSAKeyMissingN;
170
2.33k
  }
171
27.3k
  if (code == StructUtils::WRONG_TYPE) {
172
62
    return Status::JwksRSAKeyBadN;
173
62
  }
174
175
27.3k
  std::string e_str;
176
27.3k
  code = jwk_getter.GetString("e", &e_str);
177
27.3k
  if (code == StructUtils::MISSING) {
178
919
    return Status::JwksRSAKeyMissingE;
179
919
  }
180
26.3k
  if (code == StructUtils::WRONG_TYPE) {
181
319
    return Status::JwksRSAKeyBadE;
182
319
  }
183
184
26.0k
  KeyGetter e;
185
26.0k
  jwk->rsa_ = e.createRsaFromJwk(n_str, e_str);
186
26.0k
  return e.getStatus();
187
26.3k
}
188
189
Status extractJwkFromJwkEC(const ::google::protobuf::Struct& jwk_pb,
190
34.3k
                           Jwks::Pubkey* jwk) {
191
34.3k
  if (!jwk->alg_.empty() &&
192
12.5k
      (jwk->alg_.size() < 2 || jwk->alg_.compare(0, 2, "ES") != 0)) {
193
705
    return Status::JwksECKeyBadAlg;
194
705
  }
195
196
33.6k
  StructUtils jwk_getter(jwk_pb);
197
33.6k
  std::string crv_str;
198
33.6k
  auto code = jwk_getter.GetString("crv", &crv_str);
199
33.6k
  if (code == StructUtils::MISSING) {
200
13.3k
    crv_str = "";
201
13.3k
  }
202
33.6k
  if (code == StructUtils::WRONG_TYPE) {
203
1.54k
    return Status::JwksECKeyBadCrv;
204
1.54k
  }
205
32.1k
  jwk->crv_ = crv_str;
206
207
  // If both alg and crv specified, make sure they match
208
32.1k
  if (!jwk->alg_.empty() && !jwk->crv_.empty()) {
209
9.57k
    if (!((jwk->alg_ == "ES256" && jwk->crv_ == "P-256") ||
210
7.47k
          (jwk->alg_ == "ES384" && jwk->crv_ == "P-384") ||
211
5.88k
          (jwk->alg_ == "ES512" && jwk->crv_ == "P-521"))) {
212
5.42k
      return Status::JwksECKeyAlgNotCompatibleWithCrv;
213
5.42k
    }
214
9.57k
  }
215
216
  // If neither alg or crv is set, assume P-256
217
26.6k
  if (jwk->alg_.empty() && jwk->crv_.empty()) {
218
11.1k
    jwk->crv_ = "P-256";
219
11.1k
  }
220
221
26.6k
  int nid;
222
26.6k
  if (jwk->alg_ == "ES256" || jwk->crv_ == "P-256") {
223
14.4k
    nid = NID_X9_62_prime256v1;
224
14.4k
    jwk->crv_ = "P-256";
225
14.4k
  } else if (jwk->alg_ == "ES384" || jwk->crv_ == "P-384") {
226
4.79k
    nid = NID_secp384r1;
227
4.79k
    jwk->crv_ = "P-384";
228
7.46k
  } else if (jwk->alg_ == "ES512" || jwk->crv_ == "P-521") {
229
3.77k
    nid = NID_secp521r1;
230
3.77k
    jwk->crv_ = "P-521";
231
3.77k
  } else {
232
3.68k
    return Status::JwksECKeyAlgOrCrvUnsupported;
233
3.68k
  }
234
235
22.9k
  std::string x_str;
236
22.9k
  code = jwk_getter.GetString("x", &x_str);
237
22.9k
  if (code == StructUtils::MISSING) {
238
3.66k
    return Status::JwksECKeyMissingX;
239
3.66k
  }
240
19.3k
  if (code == StructUtils::WRONG_TYPE) {
241
284
    return Status::JwksECKeyBadX;
242
284
  }
243
244
19.0k
  std::string y_str;
245
19.0k
  code = jwk_getter.GetString("y", &y_str);
246
19.0k
  if (code == StructUtils::MISSING) {
247
1.60k
    return Status::JwksECKeyMissingY;
248
1.60k
  }
249
17.4k
  if (code == StructUtils::WRONG_TYPE) {
250
205
    return Status::JwksECKeyBadY;
251
205
  }
252
253
17.2k
  KeyGetter e;
254
17.2k
  jwk->ec_key_ = e.createEcKeyFromJwkEC(nid, x_str, y_str);
255
17.2k
  return e.getStatus();
256
17.4k
}
257
258
Status extractJwkFromJwkOct(const ::google::protobuf::Struct& jwk_pb,
259
23.1k
                            Jwks::Pubkey* jwk) {
260
23.1k
  if (!jwk->alg_.empty() && jwk->alg_ != "HS256" && jwk->alg_ != "HS384" &&
261
1.23k
      jwk->alg_ != "HS512") {
262
478
    return Status::JwksHMACKeyBadAlg;
263
478
  }
264
265
22.6k
  StructUtils jwk_getter(jwk_pb);
266
22.6k
  std::string k_str;
267
22.6k
  auto code = jwk_getter.GetString("k", &k_str);
268
22.6k
  if (code == StructUtils::MISSING) {
269
389
    return Status::JwksHMACKeyMissingK;
270
389
  }
271
22.3k
  if (code == StructUtils::WRONG_TYPE) {
272
78
    return Status::JwksHMACKeyBadK;
273
78
  }
274
275
22.2k
  std::string key;
276
22.2k
  if (!absl::WebSafeBase64Unescape(k_str, &key) || key.empty()) {
277
9.37k
    return Status::JwksOctBadBase64;
278
9.37k
  }
279
280
12.8k
  jwk->hmac_key_ = key;
281
12.8k
  return Status::Ok;
282
22.2k
}
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.0k
                            Jwks::Pubkey* jwk) {
287
  // alg is not required, but if present it must be EdDSA
288
15.0k
  if (!jwk->alg_.empty() && jwk->alg_ != "EdDSA") {
289
922
    return Status::JwksOKPKeyBadAlg;
290
922
  }
291
292
  // crv is required per https://tools.ietf.org/html/rfc8037#section-2
293
14.1k
  StructUtils jwk_getter(jwk_pb);
294
14.1k
  std::string crv_str;
295
14.1k
  auto code = jwk_getter.GetString("crv", &crv_str);
296
14.1k
  if (code == StructUtils::MISSING) {
297
675
    return Status::JwksOKPKeyMissingCrv;
298
675
  }
299
13.5k
  if (code == StructUtils::WRONG_TYPE) {
300
217
    return Status::JwksOKPKeyBadCrv;
301
217
  }
302
13.2k
  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.2k
  int nid;
312
13.2k
  size_t keylen;
313
13.2k
  if (jwk->crv_ == "Ed25519") {
314
11.3k
    nid = EVP_PKEY_ED25519;
315
11.3k
    keylen = ED25519_PUBLIC_KEY_LEN;
316
11.3k
  } else {
317
1.91k
    return Status::JwksOKPKeyCrvUnsupported;
318
1.91k
  }
319
320
  // x is required per https://tools.ietf.org/html/rfc8037#section-2
321
11.3k
  std::string x_str;
322
11.3k
  code = jwk_getter.GetString("x", &x_str);
323
11.3k
  if (code == StructUtils::MISSING) {
324
191
    return Status::JwksOKPKeyMissingX;
325
191
  }
326
11.1k
  if (code == StructUtils::WRONG_TYPE) {
327
197
    return Status::JwksOKPKeyBadX;
328
197
  }
329
330
10.9k
  KeyGetter e;
331
10.9k
  jwk->okp_key_raw_ = e.createRawKeyFromJwkOKP(nid, keylen, x_str);
332
10.9k
  return e.getStatus();
333
11.1k
}
334
335
141k
Status extractJwk(const ::google::protobuf::Struct& jwk_pb, Jwks::Pubkey* jwk) {
336
141k
  StructUtils jwk_getter(jwk_pb);
337
  // Check "kty" parameter, it should exist.
338
  // https://tools.ietf.org/html/rfc7517#section-4.1
339
141k
  auto code = jwk_getter.GetString("kty", &jwk->kty_);
340
141k
  if (code == StructUtils::MISSING) {
341
17.5k
    return Status::JwksMissingKty;
342
17.5k
  }
343
124k
  if (code == StructUtils::WRONG_TYPE) {
344
1.03k
    return Status::JwksBadKty;
345
1.03k
  }
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
123k
  jwk_getter.GetString("kid", &jwk->kid_);
350
123k
  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
123k
  if (jwk->kty_ == "EC") {
355
34.3k
    return extractJwkFromJwkEC(jwk_pb, jwk);
356
88.8k
  } else if (jwk->kty_ == "RSA") {
357
30.8k
    return extractJwkFromJwkRSA(jwk_pb, jwk);
358
57.9k
  } else if (jwk->kty_ == "oct") {
359
23.1k
    return extractJwkFromJwkOct(jwk_pb, jwk);
360
34.8k
  } else if (jwk->kty_ == "OKP") {
361
15.0k
    return extractJwkFromJwkOKP(jwk_pb, jwk);
362
15.0k
  }
363
19.7k
  return Status::JwksNotImplementedKty;
364
123k
}
365
366
1.60k
Status extractX509(const std::string& key, Jwks::Pubkey* jwk) {
367
1.60k
  jwk->bio_.reset(BIO_new(BIO_s_mem()));
368
1.60k
  if (BIO_write(jwk->bio_.get(), key.c_str(), key.length()) <= 0) {
369
0
    return Status::JwksX509BioWriteError;
370
0
  }
371
1.60k
  jwk->x509_.reset(
372
1.60k
      PEM_read_bio_X509(jwk->bio_.get(), nullptr, nullptr, nullptr));
373
1.60k
  if (jwk->x509_ == nullptr) {
374
1.00k
    return Status::JwksX509ParseError;
375
1.00k
  }
376
594
  bssl::UniquePtr<EVP_PKEY> tmp_pkey(X509_get_pubkey(jwk->x509_.get()));
377
594
  if (tmp_pkey == nullptr) {
378
17
    return Status::JwksX509GetPubkeyError;
379
17
  }
380
577
  jwk->rsa_.reset(EVP_PKEY_get1_RSA(tmp_pkey.get()));
381
577
  if (jwk->rsa_ == nullptr) {
382
0
    return Status::JwksX509GetPubkeyError;
383
0
  }
384
577
  return Status::Ok;
385
577
}
386
387
1.54k
bool shouldCheckX509(const ::google::protobuf::Struct& jwks_pb) {
388
1.54k
  if (jwks_pb.fields().empty()) {
389
6
    return false;
390
6
  }
391
392
2.54k
  for (const auto& kid : jwks_pb.fields()) {
393
2.54k
    if (kid.first.empty() ||
394
2.53k
        kid.second.kind_case() != google::protobuf::Value::kStringValue) {
395
351
      return false;
396
351
    }
397
2.19k
    const std::string& cert = kid.second.string_value();
398
2.19k
    if (!absl::StartsWith(cert, kX509CertPrefix) ||
399
2.10k
        !absl::EndsWith(cert, kX509CertSuffix)) {
400
116
      return false;
401
116
    }
402
2.19k
  }
403
1.07k
  return true;
404
1.54k
}
405
406
Status createFromX509(const ::google::protobuf::Struct& jwks_pb,
407
1.07k
                      std::vector<Jwks::PubkeyPtr>& keys) {
408
1.60k
  for (const auto& kid : jwks_pb.fields()) {
409
1.60k
    Jwks::PubkeyPtr key_ptr(new Jwks::Pubkey());
410
1.60k
    Status status = extractX509(kid.second.string_value(), key_ptr.get());
411
1.60k
    if (status != Status::Ok) {
412
1.02k
      return status;
413
1.02k
    }
414
415
577
    key_ptr->kid_ = kid.first;
416
577
    key_ptr->kty_ = "RSA";
417
577
    keys.push_back(std::move(key_ptr));
418
577
  }
419
48
  return Status::Ok;
420
1.07k
}
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
18.6k
JwksPtr Jwks::createFrom(const std::string& pkey, Type type) {
436
18.6k
  JwksPtr keys(new Jwks());
437
18.6k
  switch (type) {
438
9.32k
    case Type::JWKS:
439
9.32k
      keys->createFromJwksCore(pkey);
440
9.32k
      break;
441
9.32k
    case Type::PEM:
442
9.32k
      keys->createFromPemCore(pkey);
443
9.32k
      break;
444
18.6k
  }
445
18.6k
  return keys;
446
18.6k
}
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.32k
void Jwks::createFromPemCore(const std::string& pkey_pem) {
478
9.32k
  keys_.clear();
479
9.32k
  PubkeyPtr key_ptr(new Pubkey());
480
9.32k
  KeyGetter e;
481
9.32k
  bssl::UniquePtr<EVP_PKEY> evp_pkey(e.createEvpPkeyFromPem(pkey_pem));
482
9.32k
  updateStatus(e.getStatus());
483
484
9.32k
  if (evp_pkey == nullptr) {
485
9.28k
    assert(e.getStatus() != Status::Ok);
486
9.28k
    return;
487
9.28k
  }
488
9.32k
  assert(e.getStatus() == Status::Ok);
489
490
41
  switch (EVP_PKEY_id(evp_pkey.get())) {
491
24
    case EVP_PKEY_RSA:
492
24
      key_ptr->rsa_.reset(EVP_PKEY_get1_RSA(evp_pkey.get()));
493
24
      key_ptr->kty_ = "RSA";
494
24
      break;
495
17
    case EVP_PKEY_EC:
496
17
      key_ptr->ec_key_.reset(EVP_PKEY_get1_EC_KEY(evp_pkey.get()));
497
17
      key_ptr->kty_ = "EC";
498
17
      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
41
  }
519
520
41
  keys_.push_back(std::move(key_ptr));
521
41
}
522
523
9.32k
void Jwks::createFromJwksCore(const std::string& jwks_json) {
524
9.32k
  keys_.clear();
525
526
9.32k
  ::google::protobuf::util::JsonParseOptions options;
527
9.32k
  ::google::protobuf::Struct jwks_pb;
528
9.32k
  const auto status = ::google::protobuf::util::JsonStringToMessage(
529
9.32k
      jwks_json, &jwks_pb, options);
530
9.32k
  if (!status.ok()) {
531
3.96k
    updateStatus(Status::JwksParseError);
532
3.96k
    return;
533
3.96k
  }
534
535
5.36k
  const auto& fields = jwks_pb.fields();
536
5.36k
  const auto keys_it = fields.find("keys");
537
5.36k
  if (keys_it == fields.end()) {
538
    // X509 doesn't have "keys" field.
539
1.54k
    if (shouldCheckX509(jwks_pb)) {
540
1.07k
      updateStatus(createFromX509(jwks_pb, keys_));
541
1.07k
      return;
542
1.07k
    }
543
473
    updateStatus(Status::JwksNoKeys);
544
473
    return;
545
1.54k
  }
546
3.81k
  if (keys_it->second.kind_case() != google::protobuf::Value::kListValue) {
547
1
    updateStatus(Status::JwksBadKeys);
548
1
    return;
549
1
  }
550
551
245k
  for (const auto& key_value : keys_it->second.list_value().values()) {
552
245k
    if (key_value.kind_case() != ::google::protobuf::Value::kStructValue) {
553
104k
      continue;
554
104k
    }
555
141k
    PubkeyPtr key_ptr(new Pubkey());
556
141k
    Status status = extractJwk(key_value.struct_value(), key_ptr.get());
557
141k
    if (status == Status::Ok) {
558
50.9k
      keys_.push_back(std::move(key_ptr));
559
50.9k
      resetStatus(status);
560
90.8k
    } else {
561
90.8k
      updateStatus(status);
562
90.8k
    }
563
141k
  }
564
565
3.81k
  if (keys_.empty()) {
566
1.08k
    updateStatus(Status::JwksNoValidKeys);
567
2.73k
  } else {
568
2.73k
    resetStatus(Status::Ok);
569
2.73k
  }
570
3.81k
}
571
572
}  // namespace jwt_verify
573
}  // namespace google