Coverage Report

Created: 2026-06-30 06:29

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
98.7k
inline const uint8_t* castToUChar(const std::string& str) {
46
98.7k
  return reinterpret_cast<const uint8_t*>(str.c_str());
47
98.7k
}
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.45k
  bssl::UniquePtr<EVP_PKEY> createEvpPkeyFromPem(const std::string& pkey_pem) {
60
9.45k
    bssl::UniquePtr<BIO> buf(BIO_new_mem_buf(pkey_pem.data(), pkey_pem.size()));
61
9.45k
    if (buf == nullptr) {
62
0
      updateStatus(Status::JwksBioAllocError);
63
0
      return nullptr;
64
0
    }
65
9.45k
    bssl::UniquePtr<EVP_PKEY> key(
66
9.45k
        PEM_read_bio_PUBKEY(buf.get(), nullptr, nullptr, nullptr));
67
9.45k
    if (key == nullptr) {
68
9.41k
      updateStatus(Status::JwksPemBadBase64);
69
9.41k
      return nullptr;
70
9.41k
    }
71
44
    return key;
72
9.45k
  }
73
74
  bssl::UniquePtr<EC_KEY> createEcKeyFromJwkEC(int nid, const std::string& x,
75
22.6k
                                               const std::string& y) {
76
22.6k
    bssl::UniquePtr<EC_KEY> ec_key(EC_KEY_new_by_curve_name(nid));
77
22.6k
    if (!ec_key) {
78
0
      updateStatus(Status::JwksEcCreateKeyFail);
79
0
      return nullptr;
80
0
    }
81
22.6k
    bssl::UniquePtr<BIGNUM> bn_x = createBigNumFromBase64UrlString(x);
82
22.6k
    bssl::UniquePtr<BIGNUM> bn_y = createBigNumFromBase64UrlString(y);
83
22.6k
    if (!bn_x || !bn_y) {
84
      // EC public key field x or y Base64 decode fail
85
3.23k
      updateStatus(Status::JwksEcXorYBadBase64);
86
3.23k
      return nullptr;
87
3.23k
    }
88
89
19.4k
    if (EC_KEY_set_public_key_affine_coordinates(ec_key.get(), bn_x.get(),
90
19.4k
                                                 bn_y.get()) == 0) {
91
6.70k
      updateStatus(Status::JwksEcParseError);
92
6.70k
      return nullptr;
93
6.70k
    }
94
12.7k
    return ec_key;
95
19.4k
  }
96
97
  bssl::UniquePtr<RSA> createRsaFromJwk(const std::string& n,
98
31.6k
                                        const std::string& e) {
99
31.6k
    bssl::UniquePtr<BIGNUM> n_bn = createBigNumFromBase64UrlString(n);
100
31.6k
    bssl::UniquePtr<BIGNUM> e_bn = createBigNumFromBase64UrlString(e);
101
31.6k
    if (n_bn == nullptr || e_bn == nullptr) {
102
      // RSA public key field is missing or has parse error.
103
5.37k
      updateStatus(Status::JwksRsaParseError);
104
5.37k
      return nullptr;
105
5.37k
    }
106
26.2k
    if (BN_cmp_word(e_bn.get(), 3) != 0 &&
107
10.1k
        BN_cmp_word(e_bn.get(), 65537) != 0) {
108
      // non-standard key; reject it early.
109
655
      updateStatus(Status::JwksRsaParseError);
110
655
      return nullptr;
111
655
    }
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
25.6k
    bssl::UniquePtr<RSA> rsa(RSA_new());
116
25.6k
    if (rsa == nullptr ||
117
25.6k
        !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
25.6k
    n_bn.release();
124
25.6k
    e_bn.release();
125
25.6k
    if (!RSA_check_key(rsa.get())) {
126
      // Not a valid RSA public key.
127
3.12k
      updateStatus(Status::JwksRsaParseError);
128
3.12k
      return nullptr;
129
3.12k
    }
130
22.4k
    return rsa;
131
25.6k
  }
132
133
  std::string createRawKeyFromJwkOKP(int nid, size_t keylen,
134
16.2k
                                     const std::string& x) {
135
16.2k
    std::string x_decoded;
136
16.2k
    if (!absl::WebSafeBase64Unescape(x, &x_decoded)) {
137
1.54k
      updateStatus(Status::JwksOKPXBadBase64);
138
14.6k
    } else if (x_decoded.length() != keylen) {
139
1.39k
      updateStatus(Status::JwksOKPXWrongLength);
140
1.39k
    }
141
    // For OKP the "x" value is the public key and can just be used as-is
142
16.2k
    return x_decoded;
143
16.2k
  }
144
145
 private:
146
  bssl::UniquePtr<BIGNUM> createBigNumFromBase64UrlString(
147
108k
      const std::string& s) {
148
108k
    std::string s_decoded;
149
108k
    if (!absl::WebSafeBase64Unescape(s, &s_decoded)) {
150
9.85k
      return nullptr;
151
9.85k
    }
152
98.7k
    return bssl::UniquePtr<BIGNUM>(
153
98.7k
        BN_bin2bn(castToUChar(s_decoded), s_decoded.length(), NULL));
154
108k
  };
155
};
156
157
Status extractJwkFromJwkRSA(const ::google::protobuf::Struct& jwk_pb,
158
36.2k
                            Jwks::Pubkey* jwk) {
159
36.2k
  if (!jwk->alg_.empty() &&
160
3.26k
      (jwk->alg_.size() < 2 || (jwk->alg_.compare(0, 2, "RS") != 0 &&
161
1.67k
                                jwk->alg_.compare(0, 2, "PS") != 0))) {
162
1.22k
    return Status::JwksRSAKeyBadAlg;
163
1.22k
  }
164
165
35.0k
  StructUtils jwk_getter(jwk_pb);
166
35.0k
  std::string n_str;
167
35.0k
  auto code = jwk_getter.GetString("n", &n_str);
168
35.0k
  if (code == StructUtils::MISSING) {
169
2.21k
    return Status::JwksRSAKeyMissingN;
170
2.21k
  }
171
32.8k
  if (code == StructUtils::WRONG_TYPE) {
172
66
    return Status::JwksRSAKeyBadN;
173
66
  }
174
175
32.7k
  std::string e_str;
176
32.7k
  code = jwk_getter.GetString("e", &e_str);
177
32.7k
  if (code == StructUtils::MISSING) {
178
872
    return Status::JwksRSAKeyMissingE;
179
872
  }
180
31.8k
  if (code == StructUtils::WRONG_TYPE) {
181
243
    return Status::JwksRSAKeyBadE;
182
243
  }
183
184
31.6k
  KeyGetter e;
185
31.6k
  jwk->rsa_ = e.createRsaFromJwk(n_str, e_str);
186
31.6k
  return e.getStatus();
187
31.8k
}
188
189
Status extractJwkFromJwkEC(const ::google::protobuf::Struct& jwk_pb,
190
42.0k
                           Jwks::Pubkey* jwk) {
191
42.0k
  if (!jwk->alg_.empty() &&
192
15.9k
      (jwk->alg_.size() < 2 || jwk->alg_.compare(0, 2, "ES") != 0)) {
193
486
    return Status::JwksECKeyBadAlg;
194
486
  }
195
196
41.5k
  StructUtils jwk_getter(jwk_pb);
197
41.5k
  std::string crv_str;
198
41.5k
  auto code = jwk_getter.GetString("crv", &crv_str);
199
41.5k
  if (code == StructUtils::MISSING) {
200
15.2k
    crv_str = "";
201
15.2k
  }
202
41.5k
  if (code == StructUtils::WRONG_TYPE) {
203
629
    return Status::JwksECKeyBadCrv;
204
629
  }
205
40.9k
  jwk->crv_ = crv_str;
206
207
  // If both alg and crv specified, make sure they match
208
40.9k
  if (!jwk->alg_.empty() && !jwk->crv_.empty()) {
209
12.8k
    if (!((jwk->alg_ == "ES256" && jwk->crv_ == "P-256") ||
210
9.48k
          (jwk->alg_ == "ES384" && jwk->crv_ == "P-384") ||
211
6.62k
          (jwk->alg_ == "ES512" && jwk->crv_ == "P-521"))) {
212
6.08k
      return Status::JwksECKeyAlgNotCompatibleWithCrv;
213
6.08k
    }
214
12.8k
  }
215
216
  // If neither alg or crv is set, assume P-256
217
34.8k
  if (jwk->alg_.empty() && jwk->crv_.empty()) {
218
12.6k
    jwk->crv_ = "P-256";
219
12.6k
  }
220
221
34.8k
  int nid;
222
34.8k
  if (jwk->alg_ == "ES256" || jwk->crv_ == "P-256") {
223
17.8k
    nid = NID_X9_62_prime256v1;
224
17.8k
    jwk->crv_ = "P-256";
225
17.8k
  } else if (jwk->alg_ == "ES384" || jwk->crv_ == "P-384") {
226
6.29k
    nid = NID_secp384r1;
227
6.29k
    jwk->crv_ = "P-384";
228
10.7k
  } else if (jwk->alg_ == "ES512" || jwk->crv_ == "P-521") {
229
6.53k
    nid = NID_secp521r1;
230
6.53k
    jwk->crv_ = "P-521";
231
6.53k
  } else {
232
4.18k
    return Status::JwksECKeyAlgOrCrvUnsupported;
233
4.18k
  }
234
235
30.6k
  std::string x_str;
236
30.6k
  code = jwk_getter.GetString("x", &x_str);
237
30.6k
  if (code == StructUtils::MISSING) {
238
4.86k
    return Status::JwksECKeyMissingX;
239
4.86k
  }
240
25.7k
  if (code == StructUtils::WRONG_TYPE) {
241
416
    return Status::JwksECKeyBadX;
242
416
  }
243
244
25.3k
  std::string y_str;
245
25.3k
  code = jwk_getter.GetString("y", &y_str);
246
25.3k
  if (code == StructUtils::MISSING) {
247
2.46k
    return Status::JwksECKeyMissingY;
248
2.46k
  }
249
22.8k
  if (code == StructUtils::WRONG_TYPE) {
250
222
    return Status::JwksECKeyBadY;
251
222
  }
252
253
22.6k
  KeyGetter e;
254
22.6k
  jwk->ec_key_ = e.createEcKeyFromJwkEC(nid, x_str, y_str);
255
22.6k
  return e.getStatus();
256
22.8k
}
257
258
Status extractJwkFromJwkOct(const ::google::protobuf::Struct& jwk_pb,
259
48.1k
                            Jwks::Pubkey* jwk) {
260
48.1k
  if (!jwk->alg_.empty() && jwk->alg_ != "HS256" && jwk->alg_ != "HS384" &&
261
2.02k
      jwk->alg_ != "HS512") {
262
1.24k
    return Status::JwksHMACKeyBadAlg;
263
1.24k
  }
264
265
46.8k
  StructUtils jwk_getter(jwk_pb);
266
46.8k
  std::string k_str;
267
46.8k
  auto code = jwk_getter.GetString("k", &k_str);
268
46.8k
  if (code == StructUtils::MISSING) {
269
1.14k
    return Status::JwksHMACKeyMissingK;
270
1.14k
  }
271
45.7k
  if (code == StructUtils::WRONG_TYPE) {
272
216
    return Status::JwksHMACKeyBadK;
273
216
  }
274
275
45.5k
  std::string key;
276
45.5k
  if (!absl::WebSafeBase64Unescape(k_str, &key) || key.empty()) {
277
13.1k
    return Status::JwksOctBadBase64;
278
13.1k
  }
279
280
32.3k
  jwk->hmac_key_ = key;
281
32.3k
  return Status::Ok;
282
45.5k
}
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
20.9k
                            Jwks::Pubkey* jwk) {
287
  // alg is not required, but if present it must be EdDSA
288
20.9k
  if (!jwk->alg_.empty() && jwk->alg_ != "EdDSA") {
289
1.32k
    return Status::JwksOKPKeyBadAlg;
290
1.32k
  }
291
292
  // crv is required per https://tools.ietf.org/html/rfc8037#section-2
293
19.6k
  StructUtils jwk_getter(jwk_pb);
294
19.6k
  std::string crv_str;
295
19.6k
  auto code = jwk_getter.GetString("crv", &crv_str);
296
19.6k
  if (code == StructUtils::MISSING) {
297
807
    return Status::JwksOKPKeyMissingCrv;
298
807
  }
299
18.8k
  if (code == StructUtils::WRONG_TYPE) {
300
212
    return Status::JwksOKPKeyBadCrv;
301
212
  }
302
18.5k
  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
18.5k
  int nid;
312
18.5k
  size_t keylen;
313
18.5k
  if (jwk->crv_ == "Ed25519") {
314
16.8k
    nid = EVP_PKEY_ED25519;
315
16.8k
    keylen = ED25519_PUBLIC_KEY_LEN;
316
16.8k
  } else {
317
1.74k
    return Status::JwksOKPKeyCrvUnsupported;
318
1.74k
  }
319
320
  // x is required per https://tools.ietf.org/html/rfc8037#section-2
321
16.8k
  std::string x_str;
322
16.8k
  code = jwk_getter.GetString("x", &x_str);
323
16.8k
  if (code == StructUtils::MISSING) {
324
415
    return Status::JwksOKPKeyMissingX;
325
415
  }
326
16.4k
  if (code == StructUtils::WRONG_TYPE) {
327
201
    return Status::JwksOKPKeyBadX;
328
201
  }
329
330
16.2k
  KeyGetter e;
331
16.2k
  jwk->okp_key_raw_ = e.createRawKeyFromJwkOKP(nid, keylen, x_str);
332
16.2k
  return e.getStatus();
333
16.4k
}
334
335
192k
Status extractJwk(const ::google::protobuf::Struct& jwk_pb, Jwks::Pubkey* jwk) {
336
192k
  StructUtils jwk_getter(jwk_pb);
337
  // Check "kty" parameter, it should exist.
338
  // https://tools.ietf.org/html/rfc7517#section-4.1
339
192k
  auto code = jwk_getter.GetString("kty", &jwk->kty_);
340
192k
  if (code == StructUtils::MISSING) {
341
18.7k
    return Status::JwksMissingKty;
342
18.7k
  }
343
173k
  if (code == StructUtils::WRONG_TYPE) {
344
884
    return Status::JwksBadKty;
345
884
  }
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
172k
  jwk_getter.GetString("kid", &jwk->kid_);
350
172k
  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
172k
  if (jwk->kty_ == "EC") {
355
42.0k
    return extractJwkFromJwkEC(jwk_pb, jwk);
356
130k
  } else if (jwk->kty_ == "RSA") {
357
36.2k
    return extractJwkFromJwkRSA(jwk_pb, jwk);
358
94.4k
  } else if (jwk->kty_ == "oct") {
359
48.1k
    return extractJwkFromJwkOct(jwk_pb, jwk);
360
48.1k
  } else if (jwk->kty_ == "OKP") {
361
20.9k
    return extractJwkFromJwkOKP(jwk_pb, jwk);
362
20.9k
  }
363
25.4k
  return Status::JwksNotImplementedKty;
364
172k
}
365
366
1.65k
Status extractX509(const std::string& key, Jwks::Pubkey* jwk) {
367
1.65k
  jwk->bio_.reset(BIO_new(BIO_s_mem()));
368
1.65k
  if (BIO_write(jwk->bio_.get(), key.c_str(), key.length()) <= 0) {
369
0
    return Status::JwksX509BioWriteError;
370
0
  }
371
1.65k
  jwk->x509_.reset(
372
1.65k
      PEM_read_bio_X509(jwk->bio_.get(), nullptr, nullptr, nullptr));
373
1.65k
  if (jwk->x509_ == nullptr) {
374
997
    return Status::JwksX509ParseError;
375
997
  }
376
657
  bssl::UniquePtr<EVP_PKEY> tmp_pkey(X509_get_pubkey(jwk->x509_.get()));
377
657
  if (tmp_pkey == nullptr) {
378
15
    return Status::JwksX509GetPubkeyError;
379
15
  }
380
642
  jwk->rsa_.reset(EVP_PKEY_get1_RSA(tmp_pkey.get()));
381
642
  if (jwk->rsa_ == nullptr) {
382
0
    return Status::JwksX509GetPubkeyError;
383
0
  }
384
642
  return Status::Ok;
385
642
}
386
387
1.56k
bool shouldCheckX509(const ::google::protobuf::Struct& jwks_pb) {
388
1.56k
  if (jwks_pb.fields().empty()) {
389
5
    return false;
390
5
  }
391
392
2.83k
  for (const auto& kid : jwks_pb.fields()) {
393
2.83k
    if (kid.first.empty() ||
394
2.82k
        kid.second.kind_case() != google::protobuf::Value::kStringValue) {
395
378
      return false;
396
378
    }
397
2.45k
    const std::string& cert = kid.second.string_value();
398
2.45k
    if (!absl::StartsWith(cert, kX509CertPrefix) ||
399
2.36k
        !absl::EndsWith(cert, kX509CertSuffix)) {
400
125
      return false;
401
125
    }
402
2.45k
  }
403
1.05k
  return true;
404
1.56k
}
405
406
Status createFromX509(const ::google::protobuf::Struct& jwks_pb,
407
1.05k
                      std::vector<Jwks::PubkeyPtr>& keys) {
408
1.65k
  for (const auto& kid : jwks_pb.fields()) {
409
1.65k
    Jwks::PubkeyPtr key_ptr(new Jwks::Pubkey());
410
1.65k
    Status status = extractX509(kid.second.string_value(), key_ptr.get());
411
1.65k
    if (status != Status::Ok) {
412
1.01k
      return status;
413
1.01k
    }
414
415
642
    key_ptr->kid_ = kid.first;
416
642
    key_ptr->kty_ = "RSA";
417
642
    keys.push_back(std::move(key_ptr));
418
642
  }
419
45
  return Status::Ok;
420
1.05k
}
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.9k
JwksPtr Jwks::createFrom(const std::string& pkey, Type type) {
436
18.9k
  JwksPtr keys(new Jwks());
437
18.9k
  switch (type) {
438
9.45k
    case Type::JWKS:
439
9.45k
      keys->createFromJwksCore(pkey);
440
9.45k
      break;
441
9.45k
    case Type::PEM:
442
9.45k
      keys->createFromPemCore(pkey);
443
9.45k
      break;
444
18.9k
  }
445
18.9k
  return keys;
446
18.9k
}
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.45k
void Jwks::createFromPemCore(const std::string& pkey_pem) {
478
9.45k
  keys_.clear();
479
9.45k
  PubkeyPtr key_ptr(new Pubkey());
480
9.45k
  KeyGetter e;
481
9.45k
  bssl::UniquePtr<EVP_PKEY> evp_pkey(e.createEvpPkeyFromPem(pkey_pem));
482
9.45k
  updateStatus(e.getStatus());
483
484
9.45k
  if (evp_pkey == nullptr) {
485
9.41k
    assert(e.getStatus() != Status::Ok);
486
9.41k
    return;
487
9.41k
  }
488
9.45k
  assert(e.getStatus() == Status::Ok);
489
490
44
  switch (EVP_PKEY_id(evp_pkey.get())) {
491
25
    case EVP_PKEY_RSA:
492
25
      key_ptr->rsa_.reset(EVP_PKEY_get1_RSA(evp_pkey.get()));
493
25
      key_ptr->kty_ = "RSA";
494
25
      break;
495
19
    case EVP_PKEY_EC:
496
19
      key_ptr->ec_key_.reset(EVP_PKEY_get1_EC_KEY(evp_pkey.get()));
497
19
      key_ptr->kty_ = "EC";
498
19
      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
44
  }
519
520
44
  keys_.push_back(std::move(key_ptr));
521
44
}
522
523
9.45k
void Jwks::createFromJwksCore(const std::string& jwks_json) {
524
9.45k
  keys_.clear();
525
526
9.45k
  ::google::protobuf::util::JsonParseOptions options;
527
9.45k
  ::google::protobuf::Struct jwks_pb;
528
9.45k
  const auto status = ::google::protobuf::util::JsonStringToMessage(
529
9.45k
      jwks_json, &jwks_pb, options);
530
9.45k
  if (!status.ok()) {
531
4.11k
    updateStatus(Status::JwksParseError);
532
4.11k
    return;
533
4.11k
  }
534
535
5.33k
  const auto& fields = jwks_pb.fields();
536
5.33k
  const auto keys_it = fields.find("keys");
537
5.33k
  if (keys_it == fields.end()) {
538
    // X509 doesn't have "keys" field.
539
1.56k
    if (shouldCheckX509(jwks_pb)) {
540
1.05k
      updateStatus(createFromX509(jwks_pb, keys_));
541
1.05k
      return;
542
1.05k
    }
543
508
    updateStatus(Status::JwksNoKeys);
544
508
    return;
545
1.56k
  }
546
3.77k
  if (keys_it->second.kind_case() != google::protobuf::Value::kListValue) {
547
3
    updateStatus(Status::JwksBadKeys);
548
3
    return;
549
3
  }
550
551
692k
  for (const auto& key_value : keys_it->second.list_value().values()) {
552
692k
    if (key_value.kind_case() != ::google::protobuf::Value::kStructValue) {
553
499k
      continue;
554
499k
    }
555
192k
    PubkeyPtr key_ptr(new Pubkey());
556
192k
    Status status = extractJwk(key_value.struct_value(), key_ptr.get());
557
192k
    if (status == Status::Ok) {
558
80.8k
      keys_.push_back(std::move(key_ptr));
559
80.8k
      resetStatus(status);
560
111k
    } else {
561
111k
      updateStatus(status);
562
111k
    }
563
192k
  }
564
565
3.77k
  if (keys_.empty()) {
566
1.15k
    updateStatus(Status::JwksNoValidKeys);
567
2.61k
  } else {
568
2.61k
    resetStatus(Status::Ok);
569
2.61k
  }
570
3.77k
}
571
572
}  // namespace jwt_verify
573
}  // namespace google