Coverage Report

Created: 2023-08-17 06:18

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