Coverage Report

Created: 2023-06-07 07:04

/proc/self/cwd/src/jwks.cc
Line
Count
Source (jump to first uncovered line)
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.2k
inline const uint8_t* castToUChar(const std::string& str) {
46
79.2k
  return reinterpret_cast<const uint8_t*>(str.c_str());
47
79.2k
}
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
10.4k
  bssl::UniquePtr<EVP_PKEY> createEvpPkeyFromPem(const std::string& pkey_pem) {
60
10.4k
    bssl::UniquePtr<BIO> buf(BIO_new_mem_buf(pkey_pem.data(), pkey_pem.size()));
61
10.4k
    if (buf == nullptr) {
62
0
      updateStatus(Status::JwksBioAllocError);
63
0
      return nullptr;
64
0
    }
65
10.4k
    bssl::UniquePtr<EVP_PKEY> key(
66
10.4k
        PEM_read_bio_PUBKEY(buf.get(), nullptr, nullptr, nullptr));
67
10.4k
    if (key == nullptr) {
68
10.4k
      updateStatus(Status::JwksPemBadBase64);
69
10.4k
      return nullptr;
70
10.4k
    }
71
17
    return key;
72
10.4k
  }
73
74
  bssl::UniquePtr<EC_KEY> createEcKeyFromJwkEC(int nid, const std::string& x,
75
17.8k
                                               const std::string& y) {
76
17.8k
    bssl::UniquePtr<EC_KEY> ec_key(EC_KEY_new_by_curve_name(nid));
77
17.8k
    if (!ec_key) {
78
0
      updateStatus(Status::JwksEcCreateKeyFail);
79
0
      return nullptr;
80
0
    }
81
17.8k
    bssl::UniquePtr<BIGNUM> bn_x = createBigNumFromBase64UrlString(x);
82
17.8k
    bssl::UniquePtr<BIGNUM> bn_y = createBigNumFromBase64UrlString(y);
83
17.8k
    if (!bn_x || !bn_y) {
84
      // EC public key field x or y Base64 decode fail
85
2.36k
      updateStatus(Status::JwksEcXorYBadBase64);
86
2.36k
      return nullptr;
87
2.36k
    }
88
89
15.5k
    if (EC_KEY_set_public_key_affine_coordinates(ec_key.get(), bn_x.get(),
90
15.5k
                                                 bn_y.get()) == 0) {
91
4.03k
      updateStatus(Status::JwksEcParseError);
92
4.03k
      return nullptr;
93
4.03k
    }
94
11.4k
    return ec_key;
95
15.5k
  }
96
97
  bssl::UniquePtr<RSA> createRsaFromJwk(const std::string& n,
98
26.6k
                                        const std::string& e) {
99
26.6k
    bssl::UniquePtr<BIGNUM> n_bn = createBigNumFromBase64UrlString(n);
100
26.6k
    bssl::UniquePtr<BIGNUM> e_bn = createBigNumFromBase64UrlString(e);
101
26.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
21.2k
    if (BN_cmp_word(e_bn.get(), 3) != 0 &&
107
21.2k
        BN_cmp_word(e_bn.get(), 65537) != 0) {
108
      // non-standard key; reject it early.
109
1.66k
      updateStatus(Status::JwksRsaParseError);
110
1.66k
      return nullptr;
111
1.66k
    }
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
19.6k
    bssl::UniquePtr<RSA> rsa(RSA_new());
116
19.6k
    if (rsa == nullptr ||
117
19.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
19.6k
    n_bn.release();
124
19.6k
    e_bn.release();
125
19.6k
    if (!RSA_check_key(rsa.get())) {
126
      // Not a valid RSA public key.
127
4.13k
      updateStatus(Status::JwksRsaParseError);
128
4.13k
      return nullptr;
129
4.13k
    }
130
15.4k
    return rsa;
131
19.6k
  }
132
133
  std::string createRawKeyFromJwkOKP(int nid, size_t keylen,
134
21.5k
                                     const std::string& x) {
135
21.5k
    std::string x_decoded;
136
21.5k
    if (!absl::WebSafeBase64Unescape(x, &x_decoded)) {
137
1.56k
      updateStatus(Status::JwksOKPXBadBase64);
138
20.0k
    } else if (x_decoded.length() != keylen) {
139
1.44k
      updateStatus(Status::JwksOKPXWrongLength);
140
1.44k
    }
141
    // For OKP the "x" value is the public key and can just be used as-is
142
21.5k
    return x_decoded;
143
21.5k
  }
144
145
 private:
146
  bssl::UniquePtr<BIGNUM> createBigNumFromBase64UrlString(
147
89.0k
      const std::string& s) {
148
89.0k
    std::string s_decoded;
149
89.0k
    if (!absl::WebSafeBase64Unescape(s, &s_decoded)) {
150
9.85k
      return nullptr;
151
9.85k
    }
152
79.2k
    return bssl::UniquePtr<BIGNUM>(
153
79.2k
        BN_bin2bn(castToUChar(s_decoded), s_decoded.length(), NULL));
154
89.0k
  };
155
};
156
157
Status extractJwkFromJwkRSA(const ::google::protobuf::Struct& jwk_pb,
158
34.1k
                            Jwks::Pubkey* jwk) {
159
34.1k
  if (!jwk->alg_.empty() &&
160
34.1k
      (jwk->alg_.size() < 2 || (jwk->alg_.compare(0, 2, "RS") != 0 &&
161
5.79k
                                jwk->alg_.compare(0, 2, "PS") != 0))) {
162
1.23k
    return Status::JwksRSAKeyBadAlg;
163
1.23k
  }
164
165
32.8k
  StructUtils jwk_getter(jwk_pb);
166
32.8k
  std::string n_str;
167
32.8k
  auto code = jwk_getter.GetString("n", &n_str);
168
32.8k
  if (code == StructUtils::MISSING) {
169
4.01k
    return Status::JwksRSAKeyMissingN;
170
4.01k
  }
171
28.8k
  if (code == StructUtils::WRONG_TYPE) {
172
563
    return Status::JwksRSAKeyBadN;
173
563
  }
174
175
28.2k
  std::string e_str;
176
28.2k
  code = jwk_getter.GetString("e", &e_str);
177
28.2k
  if (code == StructUtils::MISSING) {
178
1.44k
    return Status::JwksRSAKeyMissingE;
179
1.44k
  }
180
26.8k
  if (code == StructUtils::WRONG_TYPE) {
181
200
    return Status::JwksRSAKeyBadE;
182
200
  }
183
184
26.6k
  KeyGetter e;
185
26.6k
  jwk->rsa_ = e.createRsaFromJwk(n_str, e_str);
186
26.6k
  return e.getStatus();
187
26.8k
}
188
189
Status extractJwkFromJwkEC(const ::google::protobuf::Struct& jwk_pb,
190
30.9k
                           Jwks::Pubkey* jwk) {
191
30.9k
  if (!jwk->alg_.empty() &&
192
30.9k
      (jwk->alg_.size() < 2 || jwk->alg_.compare(0, 2, "ES") != 0)) {
193
660
    return Status::JwksECKeyBadAlg;
194
660
  }
195
196
30.3k
  StructUtils jwk_getter(jwk_pb);
197
30.3k
  std::string crv_str;
198
30.3k
  auto code = jwk_getter.GetString("crv", &crv_str);
199
30.3k
  if (code == StructUtils::MISSING) {
200
14.7k
    crv_str = "";
201
14.7k
  }
202
30.3k
  if (code == StructUtils::WRONG_TYPE) {
203
195
    return Status::JwksECKeyBadCrv;
204
195
  }
205
30.1k
  jwk->crv_ = crv_str;
206
207
  // If both alg and crv specified, make sure they match
208
30.1k
  if (!jwk->alg_.empty() && !jwk->crv_.empty()) {
209
4.32k
    if (!((jwk->alg_ == "ES256" && jwk->crv_ == "P-256") ||
210
4.32k
          (jwk->alg_ == "ES384" && jwk->crv_ == "P-384") ||
211
4.32k
          (jwk->alg_ == "ES512" && jwk->crv_ == "P-521"))) {
212
3.02k
      return Status::JwksECKeyAlgNotCompatibleWithCrv;
213
3.02k
    }
214
4.32k
  }
215
216
  // If neither alg or crv is set, assume P-256
217
27.0k
  if (jwk->alg_.empty() && jwk->crv_.empty()) {
218
13.5k
    jwk->crv_ = "P-256";
219
13.5k
  }
220
221
27.0k
  int nid;
222
27.0k
  if (jwk->alg_ == "ES256" || jwk->crv_ == "P-256") {
223
13.9k
    nid = NID_X9_62_prime256v1;
224
13.9k
    jwk->crv_ = "P-256";
225
13.9k
  } else if (jwk->alg_ == "ES384" || jwk->crv_ == "P-384") {
226
4.24k
    nid = NID_secp384r1;
227
4.24k
    jwk->crv_ = "P-384";
228
8.90k
  } else if (jwk->alg_ == "ES512" || jwk->crv_ == "P-521") {
229
5.74k
    nid = NID_secp521r1;
230
5.74k
    jwk->crv_ = "P-521";
231
5.74k
  } else {
232
3.16k
    return Status::JwksECKeyAlgOrCrvUnsupported;
233
3.16k
  }
234
235
23.9k
  std::string x_str;
236
23.9k
  code = jwk_getter.GetString("x", &x_str);
237
23.9k
  if (code == StructUtils::MISSING) {
238
3.49k
    return Status::JwksECKeyMissingX;
239
3.49k
  }
240
20.4k
  if (code == StructUtils::WRONG_TYPE) {
241
235
    return Status::JwksECKeyBadX;
242
235
  }
243
244
20.1k
  std::string y_str;
245
20.1k
  code = jwk_getter.GetString("y", &y_str);
246
20.1k
  if (code == StructUtils::MISSING) {
247
2.09k
    return Status::JwksECKeyMissingY;
248
2.09k
  }
249
18.0k
  if (code == StructUtils::WRONG_TYPE) {
250
196
    return Status::JwksECKeyBadY;
251
196
  }
252
253
17.8k
  KeyGetter e;
254
17.8k
  jwk->ec_key_ = e.createEcKeyFromJwkEC(nid, x_str, y_str);
255
17.8k
  return e.getStatus();
256
18.0k
}
257
258
Status extractJwkFromJwkOct(const ::google::protobuf::Struct& jwk_pb,
259
13.6k
                            Jwks::Pubkey* jwk) {
260
13.6k
  if (!jwk->alg_.empty() && jwk->alg_ != "HS256" && jwk->alg_ != "HS384" &&
261
13.6k
      jwk->alg_ != "HS512") {
262
1.11k
    return Status::JwksHMACKeyBadAlg;
263
1.11k
  }
264
265
12.5k
  StructUtils jwk_getter(jwk_pb);
266
12.5k
  std::string k_str;
267
12.5k
  auto code = jwk_getter.GetString("k", &k_str);
268
12.5k
  if (code == StructUtils::MISSING) {
269
1.23k
    return Status::JwksHMACKeyMissingK;
270
1.23k
  }
271
11.2k
  if (code == StructUtils::WRONG_TYPE) {
272
106
    return Status::JwksHMACKeyBadK;
273
106
  }
274
275
11.1k
  std::string key;
276
11.1k
  if (!absl::WebSafeBase64Unescape(k_str, &key) || key.empty()) {
277
1.96k
    return Status::JwksOctBadBase64;
278
1.96k
  }
279
280
9.22k
  jwk->hmac_key_ = key;
281
9.22k
  return Status::Ok;
282
11.1k
}
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
25.4k
                            Jwks::Pubkey* jwk) {
287
  // alg is not required, but if present it must be EdDSA
288
25.4k
  if (!jwk->alg_.empty() && jwk->alg_ != "EdDSA") {
289
712
    return Status::JwksOKPKeyBadAlg;
290
712
  }
291
292
  // crv is required per https://tools.ietf.org/html/rfc8037#section-2
293
24.7k
  StructUtils jwk_getter(jwk_pb);
294
24.7k
  std::string crv_str;
295
24.7k
  auto code = jwk_getter.GetString("crv", &crv_str);
296
24.7k
  if (code == StructUtils::MISSING) {
297
1.17k
    return Status::JwksOKPKeyMissingCrv;
298
1.17k
  }
299
23.5k
  if (code == StructUtils::WRONG_TYPE) {
300
67
    return Status::JwksOKPKeyBadCrv;
301
67
  }
302
23.4k
  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
23.4k
  int nid;
312
23.4k
  size_t keylen;
313
23.4k
  if (jwk->crv_ == "Ed25519") {
314
21.9k
    nid = EVP_PKEY_ED25519;
315
21.9k
    keylen = ED25519_PUBLIC_KEY_LEN;
316
21.9k
  } else {
317
1.55k
    return Status::JwksOKPKeyCrvUnsupported;
318
1.55k
  }
319
320
  // x is required per https://tools.ietf.org/html/rfc8037#section-2
321
21.9k
  std::string x_str;
322
21.9k
  code = jwk_getter.GetString("x", &x_str);
323
21.9k
  if (code == StructUtils::MISSING) {
324
286
    return Status::JwksOKPKeyMissingX;
325
286
  }
326
21.6k
  if (code == StructUtils::WRONG_TYPE) {
327
66
    return Status::JwksOKPKeyBadX;
328
66
  }
329
330
21.5k
  KeyGetter e;
331
21.5k
  jwk->okp_key_raw_ = e.createRawKeyFromJwkOKP(nid, keylen, x_str);
332
21.5k
  return e.getStatus();
333
21.6k
}
334
335
138k
Status extractJwk(const ::google::protobuf::Struct& jwk_pb, Jwks::Pubkey* jwk) {
336
138k
  StructUtils jwk_getter(jwk_pb);
337
  // Check "kty" parameter, it should exist.
338
  // https://tools.ietf.org/html/rfc7517#section-4.1
339
138k
  auto code = jwk_getter.GetString("kty", &jwk->kty_);
340
138k
  if (code == StructUtils::MISSING) {
341
12.6k
    return Status::JwksMissingKty;
342
12.6k
  }
343
125k
  if (code == StructUtils::WRONG_TYPE) {
344
401
    return Status::JwksBadKty;
345
401
  }
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
125k
  jwk_getter.GetString("kid", &jwk->kid_);
350
125k
  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
125k
  if (jwk->kty_ == "EC") {
355
30.9k
    return extractJwkFromJwkEC(jwk_pb, jwk);
356
94.2k
  } else if (jwk->kty_ == "RSA") {
357
34.1k
    return extractJwkFromJwkRSA(jwk_pb, jwk);
358
60.1k
  } else if (jwk->kty_ == "oct") {
359
13.6k
    return extractJwkFromJwkOct(jwk_pb, jwk);
360
46.5k
  } else if (jwk->kty_ == "OKP") {
361
25.4k
    return extractJwkFromJwkOKP(jwk_pb, jwk);
362
25.4k
  }
363
21.0k
  return Status::JwksNotImplementedKty;
364
125k
}
365
366
1.10k
Status extractX509(const std::string& key, Jwks::Pubkey* jwk) {
367
1.10k
  jwk->bio_.reset(BIO_new(BIO_s_mem()));
368
1.10k
  if (BIO_write(jwk->bio_.get(), key.c_str(), key.length()) <= 0) {
369
0
    return Status::JwksX509BioWriteError;
370
0
  }
371
1.10k
  jwk->x509_.reset(
372
1.10k
      PEM_read_bio_X509(jwk->bio_.get(), nullptr, nullptr, nullptr));
373
1.10k
  if (jwk->x509_ == nullptr) {
374
1.09k
    return Status::JwksX509ParseError;
375
1.09k
  }
376
13
  bssl::UniquePtr<EVP_PKEY> tmp_pkey(X509_get_pubkey(jwk->x509_.get()));
377
13
  if (tmp_pkey == nullptr) {
378
3
    return Status::JwksX509GetPubkeyError;
379
3
  }
380
10
  jwk->rsa_.reset(EVP_PKEY_get1_RSA(tmp_pkey.get()));
381
10
  if (jwk->rsa_ == nullptr) {
382
0
    return Status::JwksX509GetPubkeyError;
383
0
  }
384
10
  return Status::Ok;
385
10
}
386
387
1.79k
bool shouldCheckX509(const ::google::protobuf::Struct& jwks_pb) {
388
1.79k
  if (jwks_pb.fields().empty()) {
389
3
    return false;
390
3
  }
391
392
2.46k
  for (const auto& kid : jwks_pb.fields()) {
393
2.46k
    if (kid.first.empty() ||
394
2.46k
        kid.second.kind_case() != google::protobuf::Value::kStringValue) {
395
575
      return false;
396
575
    }
397
1.89k
    const std::string& cert = kid.second.string_value();
398
1.89k
    if (!absl::StartsWith(cert, kX509CertPrefix) ||
399
1.89k
        !absl::EndsWith(cert, kX509CertSuffix)) {
400
109
      return false;
401
109
    }
402
1.89k
  }
403
1.10k
  return true;
404
1.79k
}
405
406
Status createFromX509(const ::google::protobuf::Struct& jwks_pb,
407
1.10k
                      std::vector<Jwks::PubkeyPtr>& keys) {
408
1.10k
  for (const auto& kid : jwks_pb.fields()) {
409
1.10k
    Jwks::PubkeyPtr key_ptr(new Jwks::Pubkey());
410
1.10k
    Status status = extractX509(kid.second.string_value(), key_ptr.get());
411
1.10k
    if (status != Status::Ok) {
412
1.09k
      return status;
413
1.09k
    }
414
415
10
    key_ptr->kid_ = kid.first;
416
10
    key_ptr->kty_ = "RSA";
417
10
    keys.push_back(std::move(key_ptr));
418
10
  }
419
10
  return Status::Ok;
420
1.10k
}
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
20.9k
JwksPtr Jwks::createFrom(const std::string& pkey, Type type) {
436
20.9k
  JwksPtr keys(new Jwks());
437
20.9k
  switch (type) {
438
10.4k
    case Type::JWKS:
439
10.4k
      keys->createFromJwksCore(pkey);
440
10.4k
      break;
441
10.4k
    case Type::PEM:
442
10.4k
      keys->createFromPemCore(pkey);
443
10.4k
      break;
444
20.9k
  }
445
20.9k
  return keys;
446
20.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
10.4k
void Jwks::createFromPemCore(const std::string& pkey_pem) {
478
10.4k
  keys_.clear();
479
10.4k
  PubkeyPtr key_ptr(new Pubkey());
480
10.4k
  KeyGetter e;
481
10.4k
  bssl::UniquePtr<EVP_PKEY> evp_pkey(e.createEvpPkeyFromPem(pkey_pem));
482
10.4k
  updateStatus(e.getStatus());
483
484
10.4k
  if (evp_pkey == nullptr) {
485
10.4k
    assert(e.getStatus() != Status::Ok);
486
10.4k
    return;
487
10.4k
  }
488
17
  assert(e.getStatus() == Status::Ok);
489
490
17
  switch (EVP_PKEY_id(evp_pkey.get())) {
491
13
    case EVP_PKEY_RSA:
492
13
      key_ptr->rsa_.reset(EVP_PKEY_get1_RSA(evp_pkey.get()));
493
13
      key_ptr->kty_ = "RSA";
494
13
      break;
495
4
    case EVP_PKEY_EC:
496
4
      key_ptr->ec_key_.reset(EVP_PKEY_get1_EC_KEY(evp_pkey.get()));
497
4
      key_ptr->kty_ = "EC";
498
4
      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
17
  }
519
520
17
  keys_.push_back(std::move(key_ptr));
521
17
}
522
523
10.4k
void Jwks::createFromJwksCore(const std::string& jwks_json) {
524
10.4k
  keys_.clear();
525
526
10.4k
  ::google::protobuf::util::JsonParseOptions options;
527
10.4k
  ::google::protobuf::Struct jwks_pb;
528
10.4k
  const auto status = ::google::protobuf::util::JsonStringToMessage(
529
10.4k
      jwks_json, &jwks_pb, options);
530
10.4k
  if (!status.ok()) {
531
4.60k
    updateStatus(Status::JwksParseError);
532
4.60k
    return;
533
4.60k
  }
534
535
5.87k
  const auto& fields = jwks_pb.fields();
536
5.87k
  const auto keys_it = fields.find("keys");
537
5.87k
  if (keys_it == fields.end()) {
538
    // X509 doesn't have "keys" field.
539
1.79k
    if (shouldCheckX509(jwks_pb)) {
540
1.10k
      updateStatus(createFromX509(jwks_pb, keys_));
541
1.10k
      return;
542
1.10k
    }
543
687
    updateStatus(Status::JwksNoKeys);
544
687
    return;
545
1.79k
  }
546
4.07k
  if (keys_it->second.kind_case() != google::protobuf::Value::kListValue) {
547
3
    updateStatus(Status::JwksBadKeys);
548
3
    return;
549
3
  }
550
551
2.07M
  for (const auto& key_value : keys_it->second.list_value().values()) {
552
2.07M
    if (key_value.kind_case() != ::google::protobuf::Value::kStructValue) {
553
1.93M
      continue;
554
1.93M
    }
555
138k
    PubkeyPtr key_ptr(new Pubkey());
556
138k
    Status status = extractJwk(key_value.struct_value(), key_ptr.get());
557
138k
    if (status == Status::Ok) {
558
54.7k
      keys_.push_back(std::move(key_ptr));
559
54.7k
      resetStatus(status);
560
83.4k
    } else {
561
83.4k
      updateStatus(status);
562
83.4k
    }
563
138k
  }
564
565
4.07k
  if (keys_.empty()) {
566
1.26k
    updateStatus(Status::JwksNoValidKeys);
567
2.81k
  } else {
568
2.81k
    resetStatus(Status::Ok);
569
2.81k
  }
570
4.07k
}
571
572
}  // namespace jwt_verify
573
}  // namespace google