jwt_verifier.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright 2015 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
20 
22 
23 #include <limits.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include <map>
28 #include <memory>
29 #include <string>
30 #include <utility>
31 #include <vector>
32 
33 #include <openssl/bio.h>
34 #include <openssl/bn.h>
35 #include <openssl/crypto.h>
36 #include <openssl/evp.h>
37 #include <openssl/pem.h>
38 #include <openssl/rsa.h>
39 #include <openssl/x509.h>
40 
41 #include "absl/status/statusor.h"
42 #include "absl/strings/string_view.h"
43 
44 #include <grpc/grpc.h>
45 #include <grpc/slice.h>
46 #include <grpc/support/alloc.h>
47 #include <grpc/support/log.h>
49 #include <grpc/support/time.h>
50 
63 #include "src/core/lib/slice/b64.h"
67 #include "src/core/tsi/ssl_types.h"
68 
69 using grpc_core::Json;
70 
71 /* --- Utils. --- */
72 
75  switch (status) {
77  return "OK";
79  return "BAD_SIGNATURE";
81  return "BAD_FORMAT";
83  return "BAD_AUDIENCE";
85  return "KEY_RETRIEVAL_ERROR";
87  return "TIME_CONSTRAINT_FAILURE";
89  return "GENERIC_ERROR";
90  default:
91  return "UNKNOWN";
92  }
93 }
94 
95 static const EVP_MD* evp_md_from_alg(const char* alg) {
96  if (strcmp(alg, "RS256") == 0) {
97  return EVP_sha256();
98  } else if (strcmp(alg, "RS384") == 0) {
99  return EVP_sha384();
100  } else if (strcmp(alg, "RS512") == 0) {
101  return EVP_sha512();
102  } else {
103  return nullptr;
104  }
105 }
106 
107 static Json parse_json_part_from_jwt(const char* str, size_t len) {
109  if (GRPC_SLICE_IS_EMPTY(slice)) {
110  gpr_log(GPR_ERROR, "Invalid base64.");
111  return Json(); // JSON null
112  }
115  Json json = Json::Parse(string, &error);
116  if (!GRPC_ERROR_IS_NONE(error)) {
117  gpr_log(GPR_ERROR, "JSON parse error: %s",
120  json = Json(); // JSON null
121  }
123  return json;
124 }
125 
126 static const char* validate_string_field(const Json& json, const char* key) {
127  if (json.type() != Json::Type::STRING) {
128  gpr_log(GPR_ERROR, "Invalid %s field", key);
129  return nullptr;
130  }
131  return json.string_value().c_str();
132 }
133 
134 static gpr_timespec validate_time_field(const Json& json, const char* key) {
136  if (json.type() != Json::Type::NUMBER) {
137  gpr_log(GPR_ERROR, "Invalid %s field", key);
138  return result;
139  }
140  result.tv_sec = strtol(json.string_value().c_str(), nullptr, 10);
141  return result;
142 }
143 
144 /* --- JOSE header. see http://tools.ietf.org/html/rfc7515#section-4 --- */
145 
146 struct jose_header {
147  const char* alg;
148  const char* kid;
149  const char* typ;
150  /* TODO(jboeuf): Add others as needed (jku, jwk, x5u, x5c and so on...). */
152 };
154  h->json.Destroy();
155  gpr_free(h);
156 }
157 
159  const char* alg_value;
160  Json::Object::const_iterator it;
161  jose_header* h = grpc_core::Zalloc<jose_header>();
162  if (json.type() != Json::Type::OBJECT) {
163  gpr_log(GPR_ERROR, "JSON value is not an object");
164  goto error;
165  }
166  // Check alg field.
167  it = json.object_value().find("alg");
168  if (it == json.object_value().end()) {
169  gpr_log(GPR_ERROR, "Missing alg field.");
170  goto error;
171  }
172  /* We only support RSA-1.5 signatures for now.
173  Beware of this if we add HMAC support:
174  https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/
175  */
176  alg_value = it->second.string_value().c_str();
177  if (it->second.type() != Json::Type::STRING ||
178  strncmp(alg_value, "RS", 2) != 0 ||
179  evp_md_from_alg(alg_value) == nullptr) {
180  gpr_log(GPR_ERROR, "Invalid alg field");
181  goto error;
182  }
183  h->alg = alg_value;
184  // Check typ field.
185  it = json.object_value().find("typ");
186  if (it != json.object_value().end()) {
187  h->typ = validate_string_field(it->second, "typ");
188  if (h->typ == nullptr) goto error;
189  }
190  // Check kid field.
191  it = json.object_value().find("kid");
192  if (it != json.object_value().end()) {
193  h->kid = validate_string_field(it->second, "kid");
194  if (h->kid == nullptr) goto error;
195  }
196  h->json.Init(std::move(json));
197  return h;
198 
199 error:
201  return nullptr;
202 }
203 
204 /* --- JWT claims. see http://tools.ietf.org/html/rfc7519#section-4.1 */
205 
207  /* Well known properties already parsed. */
208  const char* sub;
209  const char* iss;
210  const char* aud;
211  const char* jti;
215 
217 };
218 
220  claims->json.Destroy();
221  gpr_free(claims);
222 }
223 
225  if (claims == nullptr) return nullptr;
226  return claims->json.get();
227 }
228 
229 const char* grpc_jwt_claims_subject(const grpc_jwt_claims* claims) {
230  if (claims == nullptr) return nullptr;
231  return claims->sub;
232 }
233 
234 const char* grpc_jwt_claims_issuer(const grpc_jwt_claims* claims) {
235  if (claims == nullptr) return nullptr;
236  return claims->iss;
237 }
238 
239 const char* grpc_jwt_claims_id(const grpc_jwt_claims* claims) {
240  if (claims == nullptr) return nullptr;
241  return claims->jti;
242 }
243 
244 const char* grpc_jwt_claims_audience(const grpc_jwt_claims* claims) {
245  if (claims == nullptr) return nullptr;
246  return claims->aud;
247 }
248 
250  if (claims == nullptr) return gpr_inf_past(GPR_CLOCK_REALTIME);
251  return claims->iat;
252 }
253 
255  if (claims == nullptr) return gpr_inf_future(GPR_CLOCK_REALTIME);
256  return claims->exp;
257 }
258 
260  if (claims == nullptr) return gpr_inf_past(GPR_CLOCK_REALTIME);
261  return claims->nbf;
262 }
263 
265  grpc_jwt_claims* claims = grpc_core::Zalloc<grpc_jwt_claims>();
266  claims->json.Init(std::move(json));
270 
271  /* Per the spec, all fields are optional. */
272  for (const auto& p : claims->json->object_value()) {
273  if (p.first == "sub") {
274  claims->sub = validate_string_field(p.second, "sub");
275  if (claims->sub == nullptr) goto error;
276  } else if (p.first == "iss") {
277  claims->iss = validate_string_field(p.second, "iss");
278  if (claims->iss == nullptr) goto error;
279  } else if (p.first == "aud") {
280  claims->aud = validate_string_field(p.second, "aud");
281  if (claims->aud == nullptr) goto error;
282  } else if (p.first == "jti") {
283  claims->jti = validate_string_field(p.second, "jti");
284  if (claims->jti == nullptr) goto error;
285  } else if (p.first == "iat") {
286  claims->iat = validate_time_field(p.second, "iat");
287  if (gpr_time_cmp(claims->iat, gpr_time_0(GPR_CLOCK_REALTIME)) == 0) {
288  goto error;
289  }
290  } else if (p.first == "exp") {
291  claims->exp = validate_time_field(p.second, "exp");
292  if (gpr_time_cmp(claims->exp, gpr_time_0(GPR_CLOCK_REALTIME)) == 0) {
293  goto error;
294  }
295  } else if (p.first == "nbf") {
296  claims->nbf = validate_time_field(p.second, "nbf");
297  if (gpr_time_cmp(claims->nbf, gpr_time_0(GPR_CLOCK_REALTIME)) == 0) {
298  goto error;
299  }
300  }
301  }
302  return claims;
303 
304 error:
305  grpc_jwt_claims_destroy(claims);
306  return nullptr;
307 }
308 
310  const char* audience) {
311  gpr_timespec skewed_now;
312  int audience_ok;
313 
314  GPR_ASSERT(claims != nullptr);
315 
316  skewed_now =
318  if (gpr_time_cmp(skewed_now, claims->nbf) < 0) {
319  gpr_log(GPR_ERROR, "JWT is not valid yet.");
321  }
322  skewed_now =
324  if (gpr_time_cmp(skewed_now, claims->exp) > 0) {
325  gpr_log(GPR_ERROR, "JWT is expired.");
327  }
328 
329  /* This should be probably up to the upper layer to decide but let's harcode
330  the 99% use case here for email issuers, where the JWT must be self
331  issued. */
332  if (grpc_jwt_issuer_email_domain(claims->iss) != nullptr &&
333  claims->sub != nullptr && strcmp(claims->iss, claims->sub) != 0) {
335  "Email issuer (%s) cannot assert another subject (%s) than itself.",
336  claims->iss, claims->sub);
338  }
339 
340  if (audience == nullptr) {
341  audience_ok = claims->aud == nullptr;
342  } else {
343  audience_ok = claims->aud != nullptr && strcmp(audience, claims->aud) == 0;
344  }
345  if (!audience_ok) {
346  gpr_log(GPR_ERROR, "Audience mismatch: expected %s and found %s.",
347  audience == nullptr ? "NULL" : audience,
348  claims->aud == nullptr ? "NULL" : claims->aud);
350  }
351  return GRPC_JWT_VERIFIER_OK;
352 }
353 
354 /* --- verifier_cb_ctx object. --- */
355 
356 typedef enum {
359  HTTP_RESPONSE_COUNT /* must be last */
361 
367  char* audience;
370  void* user_data;
374 };
375 /* Takes ownership of the header, claims and signature. */
378  grpc_jwt_claims* claims, const char* audience, const grpc_slice& signature,
379  const char* signed_jwt, size_t signed_jwt_len, void* user_data,
381  grpc_core::ApplicationCallbackExecCtx callback_exec_ctx;
384  ctx->verifier = verifier;
385  ctx->pollent = grpc_polling_entity_create_from_pollset(pollset);
386  ctx->header = header;
387  ctx->audience = gpr_strdup(audience);
388  ctx->claims = claims;
389  ctx->signature = signature;
390  ctx->signed_data = grpc_slice_from_copied_buffer(signed_jwt, signed_jwt_len);
391  ctx->user_data = user_data;
392  ctx->user_cb = cb;
393  return ctx;
394 }
395 
397  if (ctx->audience != nullptr) gpr_free(ctx->audience);
398  if (ctx->claims != nullptr) grpc_jwt_claims_destroy(ctx->claims);
399  grpc_slice_unref_internal(ctx->signature);
400  grpc_slice_unref_internal(ctx->signed_data);
401  jose_header_destroy(ctx->header);
402  for (size_t i = 0; i < HTTP_RESPONSE_COUNT; i++) {
403  grpc_http_response_destroy(&ctx->responses[i]);
404  }
405  /* TODO: see what to do with claims... */
406  delete ctx;
407 }
408 
409 /* --- grpc_jwt_verifier object. --- */
410 
411 /* Clock skew defaults to one minute. */
413 
414 /* Max delay defaults to one minute. */
417 
421 };
424  size_t num_mappings; /* Should be very few, linear search ok. */
426 };
427 
429  if (response == nullptr) {
430  gpr_log(GPR_ERROR, "HTTP response is NULL.");
431  return Json(); // JSON null
432  }
433  if (response->status != 200) {
434  gpr_log(GPR_ERROR, "Call to http server failed with error %d.",
435  response->status);
436  return Json(); // JSON null
437  }
439  Json json = Json::Parse(
440  absl::string_view(response->body, response->body_length), &error);
441  if (!GRPC_ERROR_IS_NONE(error)) {
442  gpr_log(GPR_ERROR, "Invalid JSON found in response.");
443  return Json(); // JSON null
444  }
445  return json;
446 }
447 
448 static const Json* find_property_by_name(const Json& json, const char* name) {
449  auto it = json.object_value().find(name);
450  if (it == json.object_value().end()) {
451  return nullptr;
452  }
453  return &it->second;
454 }
455 
456 static EVP_PKEY* extract_pkey_from_x509(const char* x509_str) {
457  X509* x509 = nullptr;
458  EVP_PKEY* result = nullptr;
459  BIO* bio = BIO_new(BIO_s_mem());
460  size_t len = strlen(x509_str);
461  GPR_ASSERT(len < INT_MAX);
462  BIO_write(bio, x509_str, static_cast<int>(len));
463  x509 = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr);
464  if (x509 == nullptr) {
465  gpr_log(GPR_ERROR, "Unable to parse x509 cert.");
466  goto end;
467  }
468  result = X509_get_pubkey(x509);
469  if (result == nullptr) {
470  gpr_log(GPR_ERROR, "Cannot find public key in X509 cert.");
471  }
472 
473 end:
474  BIO_free(bio);
475  X509_free(x509);
476  return result;
477 }
478 
479 static BIGNUM* bignum_from_base64(const char* b64) {
480  BIGNUM* result = nullptr;
481  grpc_slice bin;
482 
483  if (b64 == nullptr) return nullptr;
484  bin = grpc_base64_decode(b64, 1);
485  if (GRPC_SLICE_IS_EMPTY(bin)) {
486  gpr_log(GPR_ERROR, "Invalid base64 for big num.");
487  return nullptr;
488  }
492  return result;
493 }
494 
495 #if OPENSSL_VERSION_NUMBER < 0x10100000L
496 
497 // Provide compatibility across OpenSSL 1.02 and 1.1.
498 static int RSA_set0_key(RSA* r, BIGNUM* n, BIGNUM* e, BIGNUM* d) {
499  /* If the fields n and e in r are NULL, the corresponding input
500  * parameters MUST be non-NULL for n and e. d may be
501  * left NULL (in case only the public key is used).
502  */
503  if ((r->n == nullptr && n == nullptr) || (r->e == nullptr && e == nullptr)) {
504  return 0;
505  }
506 
507  if (n != nullptr) {
508  BN_free(r->n);
509  r->n = n;
510  }
511  if (e != nullptr) {
512  BN_free(r->e);
513  r->e = e;
514  }
515  if (d != nullptr) {
516  BN_free(r->d);
517  r->d = d;
518  }
519 
520  return 1;
521 }
522 #endif // OPENSSL_VERSION_NUMBER < 0x10100000L
523 
524 static EVP_PKEY* pkey_from_jwk(const Json& json, const char* kty) {
525  RSA* rsa = nullptr;
526  EVP_PKEY* result = nullptr;
527  BIGNUM* tmp_n = nullptr;
528  BIGNUM* tmp_e = nullptr;
529  Json::Object::const_iterator it;
530 
531  GPR_ASSERT(json.type() == Json::Type::OBJECT);
532  GPR_ASSERT(kty != nullptr);
533  if (strcmp(kty, "RSA") != 0) {
534  gpr_log(GPR_ERROR, "Unsupported key type %s.", kty);
535  goto end;
536  }
537  rsa = RSA_new();
538  if (rsa == nullptr) {
539  gpr_log(GPR_ERROR, "Could not create rsa key.");
540  goto end;
541  }
542  it = json.object_value().find("n");
543  if (it == json.object_value().end()) {
544  gpr_log(GPR_ERROR, "Missing RSA public key field.");
545  goto end;
546  }
547  tmp_n = bignum_from_base64(validate_string_field(it->second, "n"));
548  if (tmp_n == nullptr) goto end;
549  it = json.object_value().find("e");
550  if (it == json.object_value().end()) {
551  gpr_log(GPR_ERROR, "Missing RSA public key field.");
552  goto end;
553  }
554  tmp_e = bignum_from_base64(validate_string_field(it->second, "e"));
555  if (tmp_e == nullptr) goto end;
556  if (!RSA_set0_key(rsa, tmp_n, tmp_e, nullptr)) {
557  gpr_log(GPR_ERROR, "Cannot set RSA key from inputs.");
558  goto end;
559  }
560  /* RSA_set0_key takes ownership on success. */
561  tmp_n = nullptr;
562  tmp_e = nullptr;
563  result = EVP_PKEY_new();
564  EVP_PKEY_set1_RSA(result, rsa); /* uprefs rsa. */
565 
566 end:
567  RSA_free(rsa);
568  BN_free(tmp_n);
569  BN_free(tmp_e);
570  return result;
571 }
572 
573 static EVP_PKEY* find_verification_key(const Json& json, const char* header_alg,
574  const char* header_kid) {
575  /* Try to parse the json as a JWK set:
576  https://tools.ietf.org/html/rfc7517#section-5. */
577  const Json* jwt_keys = find_property_by_name(json, "keys");
578  if (jwt_keys == nullptr) {
579  /* Use the google proprietary format which is:
580  { <kid1>: <x5091>, <kid2>: <x5092>, ... } */
581  const Json* cur = find_property_by_name(json, header_kid);
582  if (cur == nullptr) return nullptr;
583  return extract_pkey_from_x509(cur->string_value().c_str());
584  }
585  if (jwt_keys->type() != Json::Type::ARRAY) {
587  "Unexpected value type of keys property in jwks key set.");
588  return nullptr;
589  }
590  /* Key format is specified in:
591  https://tools.ietf.org/html/rfc7518#section-6. */
592  for (const Json& jkey : jwt_keys->array_value()) {
593  if (jkey.type() != Json::Type::OBJECT) continue;
594  const char* alg = nullptr;
595  auto it = jkey.object_value().find("alg");
596  if (it != jkey.object_value().end()) {
597  alg = validate_string_field(it->second, "alg");
598  }
599  const char* kid = nullptr;
600  it = jkey.object_value().find("kid");
601  if (it != jkey.object_value().end()) {
602  kid = validate_string_field(it->second, "kid");
603  }
604  const char* kty = nullptr;
605  it = jkey.object_value().find("kty");
606  if (it != jkey.object_value().end()) {
607  kty = validate_string_field(it->second, "kty");
608  }
609  if (alg != nullptr && kid != nullptr && kty != nullptr &&
610  strcmp(kid, header_kid) == 0 && strcmp(alg, header_alg) == 0) {
611  return pkey_from_jwk(jkey, kty);
612  }
613  }
615  "Could not find matching key in key set for kid=%s and alg=%s",
616  header_kid, header_alg);
617  return nullptr;
618 }
619 
620 static int verify_jwt_signature(EVP_PKEY* key, const char* alg,
621  const grpc_slice& signature,
622  const grpc_slice& signed_data) {
623  EVP_MD_CTX* md_ctx = EVP_MD_CTX_create();
624  const EVP_MD* md = evp_md_from_alg(alg);
625  int result = 0;
626 
627  GPR_ASSERT(md != nullptr); /* Checked before. */
628  if (md_ctx == nullptr) {
629  gpr_log(GPR_ERROR, "Could not create EVP_MD_CTX.");
630  goto end;
631  }
632  if (EVP_DigestVerifyInit(md_ctx, nullptr, md, nullptr, key) != 1) {
633  gpr_log(GPR_ERROR, "EVP_DigestVerifyInit failed.");
634  goto end;
635  }
636  if (EVP_DigestVerifyUpdate(md_ctx, GRPC_SLICE_START_PTR(signed_data),
637  GRPC_SLICE_LENGTH(signed_data)) != 1) {
638  gpr_log(GPR_ERROR, "EVP_DigestVerifyUpdate failed.");
639  goto end;
640  }
641  if (EVP_DigestVerifyFinal(md_ctx, GRPC_SLICE_START_PTR(signature),
642  GRPC_SLICE_LENGTH(signature)) != 1) {
643  gpr_log(GPR_ERROR, "JWT signature verification failed.");
644  goto end;
645  }
646  result = 1;
647 
648 end:
649  EVP_MD_CTX_destroy(md_ctx);
650  return result;
651 }
652 
653 static void on_keys_retrieved(void* user_data, grpc_error_handle /*error*/) {
654  verifier_cb_ctx* ctx = static_cast<verifier_cb_ctx*>(user_data);
655  Json json = json_from_http(&ctx->responses[HTTP_RESPONSE_KEYS]);
656  EVP_PKEY* verification_key = nullptr;
658  grpc_jwt_claims* claims = nullptr;
659 
660  if (json.type() == Json::Type::JSON_NULL) {
662  goto end;
663  }
664  verification_key =
665  find_verification_key(json, ctx->header->alg, ctx->header->kid);
666  if (verification_key == nullptr) {
667  gpr_log(GPR_ERROR, "Could not find verification key with kid %s.",
668  ctx->header->kid);
670  goto end;
671  }
672 
673  if (!verify_jwt_signature(verification_key, ctx->header->alg, ctx->signature,
674  ctx->signed_data)) {
676  goto end;
677  }
678 
679  status = grpc_jwt_claims_check(ctx->claims, ctx->audience);
680  if (status == GRPC_JWT_VERIFIER_OK) {
681  /* Pass ownership. */
682  claims = ctx->claims;
683  ctx->claims = nullptr;
684  }
685 
686 end:
687  EVP_PKEY_free(verification_key);
688  ctx->user_cb(ctx->user_data, status, claims);
690 }
691 
692 static void on_openid_config_retrieved(void* user_data,
693  grpc_error_handle /*error*/) {
694  verifier_cb_ctx* ctx = static_cast<verifier_cb_ctx*>(user_data);
695  const grpc_http_response* response = &ctx->responses[HTTP_RESPONSE_OPENID];
696  Json json = json_from_http(response);
698  memset(&req, 0, sizeof(grpc_http_request));
699  const char* jwks_uri;
700  const Json* cur;
702  char* host;
703  char* path;
704 
705  /* TODO(jboeuf): Cache the jwks_uri in order to avoid this hop next time. */
706  if (json.type() == Json::Type::JSON_NULL) goto error;
707  cur = find_property_by_name(json, "jwks_uri");
708  if (cur == nullptr) {
709  gpr_log(GPR_ERROR, "Could not find jwks_uri in openid config.");
710  goto error;
711  }
712  jwks_uri = validate_string_field(*cur, "jwks_uri");
713  if (jwks_uri == nullptr) goto error;
714  if (strstr(jwks_uri, "https://") != jwks_uri) {
715  gpr_log(GPR_ERROR, "Invalid non https jwks_uri: %s.", jwks_uri);
716  goto error;
717  }
718  jwks_uri += 8;
719  host = gpr_strdup(jwks_uri);
720  path = const_cast<char*>(strchr(jwks_uri, '/'));
721  if (path == nullptr) {
722  path = const_cast<char*>("");
723  } else {
724  *(host + (path - jwks_uri)) = '\0';
725  }
726 
727  /* TODO(ctiller): Carry the resource_quota in ctx and share it with the host
728  channel. This would allow us to cancel an authentication query when under
729  extreme memory pressure. */
730  uri = grpc_core::URI::Create("https", host, path, {} /* query params /*/,
731  "" /* fragment */);
732  if (!uri.ok()) {
733  goto error;
734  }
735  ctx->http_request = grpc_core::HttpRequest::Get(
736  std::move(*uri), nullptr /* channel args */, &ctx->pollent, &req,
738  GRPC_CLOSURE_CREATE(on_keys_retrieved, ctx, grpc_schedule_on_exec_ctx),
739  &ctx->responses[HTTP_RESPONSE_KEYS],
741  ctx->http_request->Start();
742  gpr_free(host);
743  return;
744 
745 error:
746  ctx->user_cb(ctx->user_data, GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR, nullptr);
748 }
749 
751  const char* email_domain) {
752  size_t i;
753  if (v->mappings == nullptr) return nullptr;
754  for (i = 0; i < v->num_mappings; i++) {
755  if (strcmp(email_domain, v->mappings[i].email_domain) == 0) {
756  return &v->mappings[i];
757  }
758  }
759  return nullptr;
760 }
761 
762 static void verifier_put_mapping(grpc_jwt_verifier* v, const char* email_domain,
763  const char* key_url_prefix) {
764  email_key_mapping* mapping = verifier_get_mapping(v, email_domain);
765  GPR_ASSERT(v->num_mappings < v->allocated_mappings);
766  if (mapping != nullptr) {
767  gpr_free(mapping->key_url_prefix);
768  mapping->key_url_prefix = gpr_strdup(key_url_prefix);
769  return;
770  }
771  v->mappings[v->num_mappings].email_domain = gpr_strdup(email_domain);
772  v->mappings[v->num_mappings].key_url_prefix = gpr_strdup(key_url_prefix);
773  v->num_mappings++;
774  GPR_ASSERT(v->num_mappings <= v->allocated_mappings);
775 }
776 
777 /* Very non-sophisticated way to detect an email address. Should be good
778  enough for now... */
779 const char* grpc_jwt_issuer_email_domain(const char* issuer) {
780  const char* at_sign = strchr(issuer, '@');
781  if (at_sign == nullptr) return nullptr;
782  const char* email_domain = at_sign + 1;
783  if (*email_domain == '\0') return nullptr;
784  const char* dot = strrchr(email_domain, '.');
785  if (dot == nullptr || dot == email_domain) return email_domain;
786  GPR_ASSERT(dot > email_domain);
787  /* There may be a subdomain, we just want the domain. */
788  dot = static_cast<const char*>(
789  gpr_memrchr(email_domain, '.', static_cast<size_t>(dot - email_domain)));
790  if (dot == nullptr) return email_domain;
791  return dot + 1;
792 }
793 
794 /* Takes ownership of ctx. */
796  const char* email_domain;
797  grpc_closure* http_cb;
798  char* path_prefix = nullptr;
799  const char* iss;
801  memset(&req, 0, sizeof(grpc_http_request));
802  http_response_index rsp_idx;
803  char* host;
804  char* path;
806 
807  GPR_ASSERT(ctx != nullptr && ctx->header != nullptr &&
808  ctx->claims != nullptr);
809  iss = ctx->claims->iss;
810  if (ctx->header->kid == nullptr) {
811  gpr_log(GPR_ERROR, "Missing kid in jose header.");
812  goto error;
813  }
814  if (iss == nullptr) {
815  gpr_log(GPR_ERROR, "Missing iss in claims.");
816  goto error;
817  }
818 
819  /* This code relies on:
820  https://openid.net/specs/openid-connect-discovery-1_0.html
821  Nobody seems to implement the account/email/webfinger part 2. of the spec
822  so we will rely instead on email/url mappings if we detect such an issuer.
823  Part 4, on the other hand is implemented by both google and salesforce. */
824  email_domain = grpc_jwt_issuer_email_domain(iss);
825  if (email_domain != nullptr) {
826  email_key_mapping* mapping;
827  GPR_ASSERT(ctx->verifier != nullptr);
828  mapping = verifier_get_mapping(ctx->verifier, email_domain);
829  if (mapping == nullptr) {
830  gpr_log(GPR_ERROR, "Missing mapping for issuer email.");
831  goto error;
832  }
833  host = gpr_strdup(mapping->key_url_prefix);
834  path_prefix = strchr(host, '/');
835  if (path_prefix == nullptr) {
836  gpr_asprintf(&path, "/%s", iss);
837  } else {
838  *(path_prefix++) = '\0';
839  gpr_asprintf(&path, "/%s/%s", path_prefix, iss);
840  }
841  http_cb =
842  GRPC_CLOSURE_CREATE(on_keys_retrieved, ctx, grpc_schedule_on_exec_ctx);
843  rsp_idx = HTTP_RESPONSE_KEYS;
844  } else {
845  host = gpr_strdup(strstr(iss, "https://") == iss ? iss + 8 : iss);
846  path_prefix = strchr(host, '/');
847  if (path_prefix == nullptr) {
849  } else {
850  *(path_prefix++) = 0;
851  gpr_asprintf(&path, "/%s%s", path_prefix, GRPC_OPENID_CONFIG_URL_SUFFIX);
852  }
854  grpc_schedule_on_exec_ctx);
855  rsp_idx = HTTP_RESPONSE_OPENID;
856  }
857 
858  /* TODO(ctiller): Carry the resource_quota in ctx and share it with the host
859  channel. This would allow us to cancel an authentication query when under
860  extreme memory pressure. */
861  uri = grpc_core::URI::Create("https", host, path, {} /* query params */,
862  "" /* fragment */);
863  if (!uri.ok()) {
864  goto error;
865  }
866  ctx->http_request = grpc_core::HttpRequest::Get(
867  std::move(*uri), nullptr /* channel args */, &ctx->pollent, &req,
869  &ctx->responses[rsp_idx], grpc_core::CreateHttpRequestSSLCredentials());
870  ctx->http_request->Start();
871  gpr_free(host);
872  gpr_free(path);
873  return;
874 
875 error:
876  ctx->user_cb(ctx->user_data, GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR, nullptr);
878 }
879 
881  grpc_pollset* pollset, const char* jwt,
882  const char* audience,
884  void* user_data) {
885  const char* dot = nullptr;
886  jose_header* header = nullptr;
887  grpc_jwt_claims* claims = nullptr;
888  grpc_slice signature;
889  size_t signed_jwt_len;
890  const char* cur = jwt;
891  Json json;
892 
893  GPR_ASSERT(verifier != nullptr && jwt != nullptr && audience != nullptr &&
894  cb != nullptr);
895  dot = strchr(cur, '.');
896  if (dot == nullptr) goto error;
897  json = parse_json_part_from_jwt(cur, static_cast<size_t>(dot - cur));
898  if (json.type() == Json::Type::JSON_NULL) goto error;
900  if (header == nullptr) goto error;
901 
902  cur = dot + 1;
903  dot = strchr(cur, '.');
904  if (dot == nullptr) goto error;
905  json = parse_json_part_from_jwt(cur, static_cast<size_t>(dot - cur));
906  if (json.type() == Json::Type::JSON_NULL) goto error;
907  claims = grpc_jwt_claims_from_json(std::move(json));
908  if (claims == nullptr) goto error;
909 
910  signed_jwt_len = static_cast<size_t>(dot - jwt);
911  cur = dot + 1;
912  signature = grpc_base64_decode(cur, 1);
913  if (GRPC_SLICE_IS_EMPTY(signature)) goto error;
915  verifier_cb_ctx_create(verifier, pollset, header, claims, audience,
916  signature, jwt, signed_jwt_len, user_data, cb));
917  return;
918 
919 error:
920  if (header != nullptr) jose_header_destroy(header);
921  if (claims != nullptr) grpc_jwt_claims_destroy(claims);
922  cb(user_data, GRPC_JWT_VERIFIER_BAD_FORMAT, nullptr);
923 }
924 
927  size_t num_mappings) {
928  grpc_jwt_verifier* v = grpc_core::Zalloc<grpc_jwt_verifier>();
929 
930  /* We know at least of one mapping. */
931  v->allocated_mappings = 1 + num_mappings;
932  v->mappings = static_cast<email_key_mapping*>(
933  gpr_malloc(v->allocated_mappings * sizeof(email_key_mapping)));
936  /* User-Provided mappings. */
937  if (mappings != nullptr) {
938  size_t i;
939  for (i = 0; i < num_mappings; i++) {
940  verifier_put_mapping(v, mappings[i].email_domain,
941  mappings[i].key_url_prefix);
942  }
943  }
944  return v;
945 }
946 
948  size_t i;
949  if (v == nullptr) return;
950  if (v->mappings != nullptr) {
951  for (i = 0; i < v->num_mappings; i++) {
952  gpr_free(v->mappings[i].email_domain);
953  gpr_free(v->mappings[i].key_url_prefix);
954  }
955  gpr_free(v->mappings);
956  }
957  gpr_free(v);
958 }
grpc_jwt_claims_issuer
const char * grpc_jwt_claims_issuer(const grpc_jwt_claims *claims)
Definition: jwt_verifier.cc:234
xds_interop_client.str
str
Definition: xds_interop_client.py:487
GPR_TIMESPAN
@ GPR_TIMESPAN
Definition: gpr_types.h:45
_gevent_test_main.result
result
Definition: _gevent_test_main.py:96
GRPC_JWT_VERIFIER_TIME_CONSTRAINT_FAILURE
@ GRPC_JWT_VERIFIER_TIME_CONSTRAINT_FAILURE
Definition: jwt_verifier.h:47
grpc_core::ManualConstructor::get
Type * get()
Definition: manual_constructor.h:110
bn.h
cleanup.Json
Json
Definition: cleanup.py:49
EVP_PKEY_new
#define EVP_PKEY_new
Definition: boringssl_prefix_symbols.h:1643
HTTP_RESPONSE_COUNT
@ HTTP_RESPONSE_COUNT
Definition: jwt_verifier.cc:359
grpc_jwt_verifier_verify
void grpc_jwt_verifier_verify(grpc_jwt_verifier *verifier, grpc_pollset *pollset, const char *jwt, const char *audience, grpc_jwt_verification_done_cb cb, void *user_data)
Definition: jwt_verifier.cc:880
grpc_jwt_claims::jti
const char * jti
Definition: jwt_verifier.cc:211
grpc_jwt_claims::sub
const char * sub
Definition: jwt_verifier.cc:208
EVP_sha512
const OPENSSL_EXPORT EVP_MD * EVP_sha512(void)
regen-readme.it
it
Definition: regen-readme.py:15
grpc_jwt_verifier_clock_skew
gpr_timespec grpc_jwt_verifier_clock_skew
Definition: jwt_verifier.cc:412
orphanable.h
GRPC_ERROR_NONE
#define GRPC_ERROR_NONE
Definition: error.h:234
jose_header::typ
const char * typ
Definition: jwt_verifier.cc:149
log.h
EVP_DigestVerifyInit
#define EVP_DigestVerifyInit
Definition: boringssl_prefix_symbols.h:1519
ctx
Definition: benchmark-async.c:30
grpc_jwt_verifier::num_mappings
size_t num_mappings
Definition: jwt_verifier.cc:424
grpc_core::Json::type
Type type() const
Definition: src/core/lib/json/json.h:174
GRPC_JWT_VERIFIER_OK
@ GRPC_JWT_VERIFIER_OK
Definition: jwt_verifier.h:42
memset
return memset(p, 0, total)
grpc_jwt_claims::aud
const char * aud
Definition: jwt_verifier.cc:210
validate_time_field
static gpr_timespec validate_time_field(const Json &json, const char *key)
Definition: jwt_verifier.cc:134
GRPC_JWT_VERIFIER_BAD_SIGNATURE
@ GRPC_JWT_VERIFIER_BAD_SIGNATURE
Definition: jwt_verifier.h:43
bio_st
Definition: bio.h:822
env_md_st
Definition: third_party/boringssl-with-bazel/src/crypto/fipsmodule/digest/internal.h:67
polling_entity.h
evp.h
slice.h
gpr_time_0
GPRAPI gpr_timespec gpr_time_0(gpr_clock_type type)
Definition: src/core/lib/gpr/time.cc:47
EVP_sha384
const OPENSSL_EXPORT EVP_MD * EVP_sha384(void)
TSI_SIZE_AS_SIZE
#define TSI_SIZE_AS_SIZE(x)
Definition: ssl_types.h:39
BN_bin2bn
#define BN_bin2bn
Definition: boringssl_prefix_symbols.h:900
RSA_set0_key
static int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
Definition: jwt_verifier.cc:498
bio.h
string.h
absl::string_view
Definition: abseil-cpp/absl/strings/string_view.h:167
grpc_core::StringViewFromSlice
absl::string_view StringViewFromSlice(const grpc_slice &slice)
Definition: slice_internal.h:93
gpr_free
GPRAPI void gpr_free(void *ptr)
Definition: alloc.cc:51
error
grpc_error_handle error
Definition: retry_filter.cc:499
pkey_from_jwk
static EVP_PKEY * pkey_from_jwk(const Json &json, const char *kty)
Definition: jwt_verifier.cc:524
GRPC_JWT_VERIFIER_BAD_SUBJECT
@ GRPC_JWT_VERIFIER_BAD_SUBJECT
Definition: jwt_verifier.h:48
verifier_cb_ctx::signature
grpc_slice signature
Definition: jwt_verifier.cc:368
find_property_by_name
static const Json * find_property_by_name(const Json &json, const char *name)
Definition: jwt_verifier.cc:448
grpc_core::Json::object_value
const Object & object_value() const
Definition: src/core/lib/json/json.h:177
gpr_malloc
GPRAPI void * gpr_malloc(size_t size)
Definition: alloc.cc:29
grpc_jwt_claims_expires_at
gpr_timespec grpc_jwt_claims_expires_at(const grpc_jwt_claims *claims)
Definition: jwt_verifier.cc:254
closure.h
EVP_DigestVerifyUpdate
#define EVP_DigestVerifyUpdate
Definition: boringssl_prefix_symbols.h:1520
grpc_jwt_verification_done_cb
void(* grpc_jwt_verification_done_cb)(void *user_data, grpc_jwt_verifier_status status, grpc_jwt_claims *claims)
Definition: jwt_verifier.h:106
status
absl::Status status
Definition: rls.cc:251
gpr_inf_future
GPRAPI gpr_timespec gpr_inf_future(gpr_clock_type type)
Definition: src/core/lib/gpr/time.cc:55
grpc_core::ApplicationCallbackExecCtx
Definition: exec_ctx.h:283
grpc_jwt_claims_subject
const char * grpc_jwt_claims_subject(const grpc_jwt_claims *claims)
Definition: jwt_verifier.cc:229
pem.h
ctx
static struct test_ctx ctx
Definition: test-ipc-send-recv.c:65
setup.name
name
Definition: setup.py:542
BIO_write
#define BIO_write
Definition: boringssl_prefix_symbols.h:870
BN_free
#define BN_free
Definition: boringssl_prefix_symbols.h:923
time.h
check_documentation.path
path
Definition: check_documentation.py:57
ssl_types.h
verifier_cb_ctx::pollent
grpc_polling_entity pollent
Definition: jwt_verifier.cc:364
verifier_cb_ctx::user_data
void * user_data
Definition: jwt_verifier.cc:370
xds_manager.p
p
Definition: xds_manager.py:60
GRPC_CLOSURE_CREATE
#define GRPC_CLOSURE_CREATE(cb, cb_arg, scheduler)
Definition: closure.h:160
grpc_core::CreateHttpRequestSSLCredentials
RefCountedPtr< grpc_channel_credentials > CreateHttpRequestSSLCredentials()
Definition: httpcli_security_connector.cc:208
grpc_jwt_claims::json
grpc_core::ManualConstructor< Json > json
Definition: jwt_verifier.cc:216
EVP_sha256
const OPENSSL_EXPORT EVP_MD * EVP_sha256(void)
grpc_core::ManualConstructor::Destroy
void Destroy()
Definition: manual_constructor.h:139
verifier
static void verifier(grpc_server *server, grpc_completion_queue *cq, void *)
Definition: badreq.cc:31
grpc_jwt_claims_id
const char * grpc_jwt_claims_id(const grpc_jwt_claims *claims)
Definition: jwt_verifier.cc:239
grpc_jwt_verifier_status_to_string
const char * grpc_jwt_verifier_status_to_string(grpc_jwt_verifier_status status)
Definition: jwt_verifier.cc:73
credentials.h
bin
Definition: tools/run_tests/xds_k8s_test_driver/bin/__init__.py:1
grpc_jwt_claims_destroy
void grpc_jwt_claims_destroy(grpc_jwt_claims *claims)
Definition: jwt_verifier.cc:219
extract_pkey_from_x509
static EVP_PKEY * extract_pkey_from_x509(const char *x509_str)
Definition: jwt_verifier.cc:456
env_md_ctx_st
Definition: digest.h:306
verifier_get_mapping
static email_key_mapping * verifier_get_mapping(grpc_jwt_verifier *v, const char *email_domain)
Definition: jwt_verifier.cc:750
X509_free
#define X509_free
Definition: boringssl_prefix_symbols.h:2632
grpc_jwt_issuer_email_domain
const char * grpc_jwt_issuer_email_domain(const char *issuer)
Definition: jwt_verifier.cc:779
memory.h
evp_md_from_alg
static const EVP_MD * evp_md_from_alg(const char *alg)
Definition: jwt_verifier.cc:95
grpc_base64_decode_with_len
grpc_slice grpc_base64_decode_with_len(const char *b64, size_t b64_len, int url_safe)
Definition: b64.cc:191
X509_get_pubkey
#define X509_get_pubkey
Definition: boringssl_prefix_symbols.h:2669
string_util.h
grpc_http_response
Definition: src/core/lib/http/parser.h:85
grpc_jwt_verifier_status
grpc_jwt_verifier_status
Definition: jwt_verifier.h:41
grpc_core::Json::array_value
const Array & array_value() const
Definition: src/core/lib/json/json.h:179
jwt_verifier.h
jose_header
Definition: jwt_verifier.cc:146
verifier_cb_ctx_destroy
void verifier_cb_ctx_destroy(verifier_cb_ctx *ctx)
Definition: jwt_verifier.cc:396
PEM_read_bio_X509
#define PEM_read_bio_X509
Definition: boringssl_prefix_symbols.h:1955
verifier_cb_ctx::user_cb
grpc_jwt_verification_done_cb user_cb
Definition: jwt_verifier.cc:371
verifier_put_mapping
static void verifier_put_mapping(grpc_jwt_verifier *v, const char *email_domain, const char *key_url_prefix)
Definition: jwt_verifier.cc:762
evp_pkey_st
Definition: evp.h:1046
absl::move
constexpr absl::remove_reference_t< T > && move(T &&t) noexcept
Definition: abseil-cpp/absl/utility/utility.h:221
GPR_ASSERT
#define GPR_ASSERT(x)
Definition: include/grpc/impl/codegen/log.h:94
end
char * end
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1008
http_response_index
http_response_index
Definition: jwt_verifier.cc:356
RSA_free
#define RSA_free
Definition: boringssl_prefix_symbols.h:2090
jose_header::json
grpc_core::ManualConstructor< Json > json
Definition: jwt_verifier.cc:151
gpr_time_cmp
GPRAPI int gpr_time_cmp(gpr_timespec a, gpr_timespec b)
Definition: src/core/lib/gpr/time.cc:30
gen_stats_data.c_str
def c_str(s, encoding='ascii')
Definition: gen_stats_data.py:38
Json
JSON (JavaScript Object Notation).
Definition: third_party/bloaty/third_party/protobuf/conformance/third_party/jsoncpp/json.h:227
GRPC_JWT_VERIFIER_GENERIC_ERROR
@ GRPC_JWT_VERIFIER_GENERIC_ERROR
Definition: jwt_verifier.h:49
GRPC_SLICE_IS_EMPTY
#define GRPC_SLICE_IS_EMPTY(slice)
Definition: include/grpc/impl/codegen/slice.h:112
gpr_time_sub
GPRAPI gpr_timespec gpr_time_sub(gpr_timespec a, gpr_timespec b)
Definition: src/core/lib/gpr/time.cc:168
req
static uv_connect_t req
Definition: test-connection-fail.c:30
grpc_base64_decode
grpc_slice grpc_base64_decode(const char *b64, int url_safe)
Definition: b64.cc:126
BIO_s_mem
#define BIO_s_mem
Definition: boringssl_prefix_symbols.h:839
slice
grpc_slice slice
Definition: src/core/lib/surface/server.cc:467
gpr_log
GPRAPI void gpr_log(const char *file, int line, gpr_log_severity severity, const char *format,...) GPR_PRINT_FORMAT_CHECK(4
setup.v
v
Definition: third_party/bloaty/third_party/capstone/bindings/python/setup.py:42
email_key_mapping
Definition: jwt_verifier.cc:418
grpc_polling_entity_create_from_pollset
grpc_polling_entity grpc_polling_entity_create_from_pollset(grpc_pollset *pollset)
Definition: polling_entity.cc:34
grpc_core::ManualConstructor::Init
void Init()
Definition: manual_constructor.h:119
httpcli_ssl_credentials.h
httpcli.h
GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR
@ GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR
Definition: jwt_verifier.h:46
grpc.h
grpc_jwt_claims_json
const Json * grpc_jwt_claims_json(const grpc_jwt_claims *claims)
Definition: jwt_verifier.cc:224
GRPC_GOOGLE_SERVICE_ACCOUNTS_KEY_URL_PREFIX
#define GRPC_GOOGLE_SERVICE_ACCOUNTS_KEY_URL_PREFIX
Definition: jwt_verifier.h:36
verify_jwt_signature
static int verify_jwt_signature(EVP_PKEY *key, const char *alg, const grpc_slice &signature, const grpc_slice &signed_data)
Definition: jwt_verifier.cc:620
grpc_jwt_claims_not_before
gpr_timespec grpc_jwt_claims_not_before(const grpc_jwt_claims *claims)
Definition: jwt_verifier.cc:259
EVP_PKEY_free
#define EVP_PKEY_free
Definition: boringssl_prefix_symbols.h:1625
grpc_jwt_verifier::mappings
email_key_mapping * mappings
Definition: jwt_verifier.cc:423
verifier_cb_ctx::http_request
grpc_core::OrphanablePtr< grpc_core::HttpRequest > http_request
Definition: jwt_verifier.cc:373
header
struct absl::base_internal::@2940::AllocList::Header header
gpr_memrchr
void * gpr_memrchr(const void *s, int c, size_t n)
Definition: string.cc:313
GRPC_SLICE_START_PTR
#define GRPC_SLICE_START_PTR(slice)
Definition: include/grpc/impl/codegen/slice.h:101
crypto.h
rsa.h
b64.h
grpc_jwt_claims_audience
const char * grpc_jwt_claims_audience(const grpc_jwt_claims *claims)
Definition: jwt_verifier.cc:244
grpc_slice
Definition: include/grpc/impl/codegen/slice.h:65
gpr_asprintf
GPRAPI int gpr_asprintf(char **strp, const char *format,...) GPR_PRINT_FORMAT_CHECK(2
grpc_http_response_destroy
void grpc_http_response_destroy(grpc_http_response *response)
Definition: src/core/lib/http/parser.cc:434
absl::flags_internal::Parse
bool Parse(FlagOpFn op, absl::string_view text, void *dst, std::string *error)
Definition: abseil-cpp/absl/flags/internal/flag.h:125
error.h
grpc_jwt_claims::exp
gpr_timespec exp
Definition: jwt_verifier.cc:213
grpc_polling_entity
Definition: polling_entity.h:38
BIO_new
#define BIO_new
Definition: boringssl_prefix_symbols.h:814
slice_internal.h
GPR_ERROR
#define GPR_ERROR
Definition: include/grpc/impl/codegen/log.h:57
RSA_new
#define RSA_new
Definition: boringssl_prefix_symbols.h:2110
jose_header_from_json
static jose_header * jose_header_from_json(Json json)
Definition: jwt_verifier.cc:158
d
static const fe d
Definition: curve25519_tables.h:19
gpr_now
GPRAPI gpr_timespec gpr_now(gpr_clock_type clock)
grpc_core::ExecCtx
Definition: exec_ctx.h:97
n
int n
Definition: abseil-cpp/absl/container/btree_test.cc:1080
manual_constructor.h
jose_header_destroy
static void jose_header_destroy(jose_header *h)
Definition: jwt_verifier.cc:153
GRPC_OPENID_CONFIG_URL_SUFFIX
#define GRPC_OPENID_CONFIG_URL_SUFFIX
Definition: jwt_verifier.h:34
HTTP_RESPONSE_KEYS
@ HTTP_RESPONSE_KEYS
Definition: jwt_verifier.cc:358
GRPC_JWT_VERIFIER_BAD_FORMAT
@ GRPC_JWT_VERIFIER_BAD_FORMAT
Definition: jwt_verifier.h:44
GRPC_SLICE_LENGTH
#define GRPC_SLICE_LENGTH(slice)
Definition: include/grpc/impl/codegen/slice.h:104
parse_json_part_from_jwt
static Json parse_json_part_from_jwt(const char *str, size_t len)
Definition: jwt_verifier.cc:107
find_verification_key
static EVP_PKEY * find_verification_key(const Json &json, const char *header_alg, const char *header_kid)
Definition: jwt_verifier.cc:573
on_openid_config_retrieved
static void on_openid_config_retrieved(void *user_data, grpc_error_handle)
Definition: jwt_verifier.cc:692
gpr_inf_past
GPRAPI gpr_timespec gpr_inf_past(gpr_clock_type type)
Definition: src/core/lib/gpr/time.cc:63
BIO_free
#define BIO_free
Definition: boringssl_prefix_symbols.h:787
memory_diff.cur
def cur
Definition: memory_diff.py:83
grpc_jwt_claims::iss
const char * iss
Definition: jwt_verifier.cc:209
EVP_PKEY_set1_RSA
#define EVP_PKEY_set1_RSA
Definition: boringssl_prefix_symbols.h:1653
absl::StatusOr::ok
ABSL_MUST_USE_RESULT bool ok() const
Definition: abseil-cpp/absl/status/statusor.h:491
benchmark.md
md
Definition: benchmark.py:86
EVP_MD_CTX_destroy
#define EVP_MD_CTX_destroy
Definition: boringssl_prefix_symbols.h:1565
parser.h
grpc_slice_from_copied_buffer
GPRAPI grpc_slice grpc_slice_from_copied_buffer(const char *source, size_t len)
Definition: slice/slice.cc:170
grpc_core::HttpRequest::Get
static OrphanablePtr< HttpRequest > Get(URI uri, const grpc_channel_args *args, grpc_polling_entity *pollent, const grpc_http_request *request, Timestamp deadline, grpc_closure *on_done, grpc_http_response *response, RefCountedPtr< grpc_channel_credentials > channel_creds) GRPC_MUST_USE_RESULT
Definition: httpcli.cc:69
key
const char * key
Definition: hpack_parser_table.cc:164
grpc_jwt_verifier_email_domain_key_url_mapping
Definition: jwt_verifier.h:76
verifier_cb_ctx::signed_data
grpc_slice signed_data
Definition: jwt_verifier.cc:369
verifier_cb_ctx::audience
char * audience
Definition: jwt_verifier.cc:367
x509_st
Definition: third_party/boringssl-with-bazel/src/crypto/x509/internal.h:139
verifier_cb_ctx::claims
grpc_jwt_claims * claims
Definition: jwt_verifier.cc:366
grpc_jwt_claims::nbf
gpr_timespec nbf
Definition: jwt_verifier.cc:214
gpr_time_add
GPRAPI gpr_timespec gpr_time_add(gpr_timespec a, gpr_timespec b)
Definition: src/core/lib/gpr/time.cc:135
email_key_mapping::key_url_prefix
char * key_url_prefix
Definition: jwt_verifier.cc:420
grpc_jwt_claims_from_json
grpc_jwt_claims * grpc_jwt_claims_from_json(Json json)
Definition: jwt_verifier.cc:264
exec_ctx
grpc_core::ExecCtx exec_ctx
Definition: end2end_binder_transport_test.cc:75
grpc_error_std_string
std::string grpc_error_std_string(grpc_error_handle error)
Definition: error.cc:944
grpc_jwt_verifier_create
grpc_jwt_verifier * grpc_jwt_verifier_create(const grpc_jwt_verifier_email_domain_key_url_mapping *mappings, size_t num_mappings)
Definition: jwt_verifier.cc:925
bignum_st
Definition: bn.h:957
retrieve_key_and_verify
static void retrieve_key_and_verify(verifier_cb_ctx *ctx)
Definition: jwt_verifier.cc:795
verifier_cb_ctx::header
jose_header * header
Definition: jwt_verifier.cc:365
grpc_core::URI::Create
static absl::StatusOr< URI > Create(std::string scheme, std::string authority, std::string path, std::vector< QueryParam > query_parameter_pairs, std::string fragment)
Definition: uri_parser.cc:289
alloc.h
grpc_core::OrphanablePtr
std::unique_ptr< T, Deleter > OrphanablePtr
Definition: orphanable.h:64
fix_build_deps.r
r
Definition: fix_build_deps.py:491
asyncio_get_stats.response
response
Definition: asyncio_get_stats.py:28
verifier_cb_ctx
Definition: jwt_verifier.cc:362
grpc_core::Json::string_value
const std::string & string_value() const
Definition: src/core/lib/json/json.h:175
grpc_jwt_verifier
Definition: jwt_verifier.cc:422
exec_ctx.h
grpc_jwt_verifier_max_delay
grpc_core::Duration grpc_jwt_verifier_max_delay
Definition: jwt_verifier.cc:415
slice_refcount.h
GRPC_ERROR_UNREF
#define GRPC_ERROR_UNREF(err)
Definition: error.h:262
verifier_cb_ctx::verifier
grpc_jwt_verifier * verifier
Definition: jwt_verifier.cc:363
bignum_from_base64
static BIGNUM * bignum_from_base64(const char *b64)
Definition: jwt_verifier.cc:479
grpc_jwt_claims_check
grpc_jwt_verifier_status grpc_jwt_claims_check(const grpc_jwt_claims *claims, const char *audience)
Definition: jwt_verifier.cc:309
gpr_strdup
GPRAPI char * gpr_strdup(const char *src)
Definition: string.cc:39
verifier_cb_ctx_create
static verifier_cb_ctx * verifier_cb_ctx_create(grpc_jwt_verifier *verifier, grpc_pollset *pollset, jose_header *header, grpc_jwt_claims *claims, const char *audience, const grpc_slice &signature, const char *signed_jwt, size_t signed_jwt_len, void *user_data, grpc_jwt_verification_done_cb cb)
Definition: jwt_verifier.cc:376
grpc_jwt_claims
Definition: jwt_verifier.cc:206
GRPC_GOOGLE_SERVICE_ACCOUNTS_EMAIL_DOMAIN
#define GRPC_GOOGLE_SERVICE_ACCOUNTS_EMAIL_DOMAIN
Definition: jwt_verifier.h:35
grpc_jwt_claims_issued_at
gpr_timespec grpc_jwt_claims_issued_at(const grpc_jwt_claims *claims)
Definition: jwt_verifier.cc:249
grpc_jwt_verifier_destroy
void grpc_jwt_verifier_destroy(grpc_jwt_verifier *v)
Definition: jwt_verifier.cc:947
absl::StatusOr
Definition: abseil-cpp/absl/status/statusor.h:187
uri_parser.h
rsa_st
Definition: rsa.h:732
grpc_core::ExecCtx::Now
Timestamp Now()
Definition: exec_ctx.cc:90
len
int len
Definition: abseil-cpp/absl/base/internal/low_level_alloc_test.cc:46
gpr_timespec
Definition: gpr_types.h:50
json_from_http
static Json json_from_http(const grpc_http_response *response)
Definition: jwt_verifier.cc:428
grpc_error
Definition: error_internal.h:42
EVP_DigestVerifyFinal
#define EVP_DigestVerifyFinal
Definition: boringssl_prefix_symbols.h:1518
EVP_MD_CTX_create
#define EVP_MD_CTX_create
Definition: boringssl_prefix_symbols.h:1564
email_key_mapping::email_domain
char * email_domain
Definition: jwt_verifier.cc:419
grpc_core::Duration
Definition: src/core/lib/gprpp/time.h:122
GPR_CLOCK_REALTIME
@ GPR_CLOCK_REALTIME
Definition: gpr_types.h:39
validate_string_field
static const char * validate_string_field(const Json &json, const char *key)
Definition: jwt_verifier.cc:126
grpc_pollset
Definition: bm_cq_multiple_threads.cc:37
grpc_jwt_claims::iat
gpr_timespec iat
Definition: jwt_verifier.cc:212
grpc_closure
Definition: closure.h:56
jose_header::kid
const char * kid
Definition: jwt_verifier.cc:148
grpc_jwt_verifier::allocated_mappings
size_t allocated_mappings
Definition: jwt_verifier.cc:425
GRPC_JWT_VERIFIER_BAD_AUDIENCE
@ GRPC_JWT_VERIFIER_BAD_AUDIENCE
Definition: jwt_verifier.h:45
cb
OPENSSL_EXPORT pem_password_cb * cb
Definition: pem.h:351
grpc_core::ExecCtx::Get
static ExecCtx * Get()
Definition: exec_ctx.h:205
on_keys_retrieved
static void on_keys_retrieved(void *user_data, grpc_error_handle)
Definition: jwt_verifier.cc:653
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230
grpc_slice_unref_internal
void grpc_slice_unref_internal(const grpc_slice &slice)
Definition: slice_refcount.h:39
GRPC_ERROR_IS_NONE
#define GRPC_ERROR_IS_NONE(err)
Definition: error.h:241
grpc_http_request
Definition: src/core/lib/http/parser.h:69
grpc_core::ManualConstructor< Json >
x509.h
grpc_core::Duration::Minutes
static constexpr Duration Minutes(int64_t minutes)
Definition: src/core/lib/gprpp/time.h:147
verifier_cb_ctx::responses
grpc_http_response responses[HTTP_RESPONSE_COUNT]
Definition: jwt_verifier.cc:372
port_platform.h
jose_header::alg
const char * alg
Definition: jwt_verifier.cc:147
HTTP_RESPONSE_OPENID
@ HTTP_RESPONSE_OPENID
Definition: jwt_verifier.cc:357


grpc
Author(s):
autogenerated on Fri May 16 2025 02:59:14