diff options
Diffstat (limited to 'src/core/lib/security/credentials/jwt/jwt_verifier.cc')
-rw-r--r-- | src/core/lib/security/credentials/jwt/jwt_verifier.cc | 126 |
1 files changed, 71 insertions, 55 deletions
diff --git a/src/core/lib/security/credentials/jwt/jwt_verifier.cc b/src/core/lib/security/credentials/jwt/jwt_verifier.cc index 39339f07d7..3709b83c4e 100644 --- a/src/core/lib/security/credentials/jwt/jwt_verifier.cc +++ b/src/core/lib/security/credentials/jwt/jwt_verifier.cc @@ -74,11 +74,12 @@ static const EVP_MD* evp_md_from_alg(const char* alg) { } } -static grpc_json* parse_json_part_from_jwt(const char* str, size_t len, +static grpc_json* parse_json_part_from_jwt(grpc_exec_ctx* exec_ctx, + const char* str, size_t len, grpc_slice* buffer) { grpc_json* json; - *buffer = grpc_base64_decode_with_len(str, len, 1); + *buffer = grpc_base64_decode_with_len(exec_ctx, str, len, 1); if (GRPC_SLICE_IS_EMPTY(*buffer)) { gpr_log(GPR_ERROR, "Invalid base64."); return nullptr; @@ -86,7 +87,7 @@ static grpc_json* parse_json_part_from_jwt(const char* str, size_t len, json = grpc_json_parse_string_with_len((char*)GRPC_SLICE_START_PTR(*buffer), GRPC_SLICE_LENGTH(*buffer)); if (json == nullptr) { - grpc_slice_unref_internal(*buffer); + grpc_slice_unref_internal(exec_ctx, *buffer); gpr_log(GPR_ERROR, "JSON parsing error."); } return json; @@ -122,13 +123,14 @@ typedef struct { grpc_slice buffer; } jose_header; -static void jose_header_destroy(jose_header* h) { - grpc_slice_unref_internal(h->buffer); +static void jose_header_destroy(grpc_exec_ctx* exec_ctx, jose_header* h) { + grpc_slice_unref_internal(exec_ctx, h->buffer); gpr_free(h); } /* Takes ownership of json and buffer. */ -static jose_header* jose_header_from_json(grpc_json* json, grpc_slice buffer) { +static jose_header* jose_header_from_json(grpc_exec_ctx* exec_ctx, + grpc_json* json, grpc_slice buffer) { grpc_json* cur; jose_header* h = (jose_header*)gpr_zalloc(sizeof(jose_header)); h->buffer = buffer; @@ -162,7 +164,7 @@ static jose_header* jose_header_from_json(grpc_json* json, grpc_slice buffer) { error: grpc_json_destroy(json); - jose_header_destroy(h); + jose_header_destroy(exec_ctx, h); return nullptr; } @@ -182,9 +184,9 @@ struct grpc_jwt_claims { grpc_slice buffer; }; -void grpc_jwt_claims_destroy(grpc_jwt_claims* claims) { +void grpc_jwt_claims_destroy(grpc_exec_ctx* exec_ctx, grpc_jwt_claims* claims) { grpc_json_destroy(claims->json); - grpc_slice_unref_internal(claims->buffer); + grpc_slice_unref_internal(exec_ctx, claims->buffer); gpr_free(claims); } @@ -229,7 +231,8 @@ gpr_timespec grpc_jwt_claims_not_before(const grpc_jwt_claims* claims) { } /* Takes ownership of json and buffer even in case of failure. */ -grpc_jwt_claims* grpc_jwt_claims_from_json(grpc_json* json, grpc_slice buffer) { +grpc_jwt_claims* grpc_jwt_claims_from_json(grpc_exec_ctx* exec_ctx, + grpc_json* json, grpc_slice buffer) { grpc_json* cur; grpc_jwt_claims* claims = (grpc_jwt_claims*)gpr_malloc(sizeof(grpc_jwt_claims)); @@ -271,7 +274,7 @@ grpc_jwt_claims* grpc_jwt_claims_from_json(grpc_json* json, grpc_slice buffer) { return claims; error: - grpc_jwt_claims_destroy(claims); + grpc_jwt_claims_destroy(exec_ctx, claims); return nullptr; } @@ -347,7 +350,7 @@ static verifier_cb_ctx* verifier_cb_ctx_create( grpc_jwt_claims* claims, const char* audience, grpc_slice signature, const char* signed_jwt, size_t signed_jwt_len, void* user_data, grpc_jwt_verification_done_cb cb) { - grpc_core::ExecCtx exec_ctx; + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; verifier_cb_ctx* ctx = (verifier_cb_ctx*)gpr_zalloc(sizeof(verifier_cb_ctx)); ctx->verifier = verifier; ctx->pollent = grpc_polling_entity_create_from_pollset(pollset); @@ -358,16 +361,16 @@ static verifier_cb_ctx* verifier_cb_ctx_create( ctx->signed_data = grpc_slice_from_copied_buffer(signed_jwt, signed_jwt_len); ctx->user_data = user_data; ctx->user_cb = cb; - + grpc_exec_ctx_finish(&exec_ctx); return ctx; } -void verifier_cb_ctx_destroy(verifier_cb_ctx* ctx) { +void verifier_cb_ctx_destroy(grpc_exec_ctx* exec_ctx, verifier_cb_ctx* ctx) { if (ctx->audience != nullptr) gpr_free(ctx->audience); - if (ctx->claims != nullptr) grpc_jwt_claims_destroy(ctx->claims); - grpc_slice_unref_internal(ctx->signature); - grpc_slice_unref_internal(ctx->signed_data); - jose_header_destroy(ctx->header); + if (ctx->claims != nullptr) grpc_jwt_claims_destroy(exec_ctx, ctx->claims); + grpc_slice_unref_internal(exec_ctx, ctx->signature); + grpc_slice_unref_internal(exec_ctx, ctx->signed_data); + jose_header_destroy(exec_ctx, ctx->header); for (size_t i = 0; i < HTTP_RESPONSE_COUNT; i++) { grpc_http_response_destroy(&ctx->responses[i]); } @@ -447,19 +450,19 @@ end: return result; } -static BIGNUM* bignum_from_base64(const char* b64) { +static BIGNUM* bignum_from_base64(grpc_exec_ctx* exec_ctx, const char* b64) { BIGNUM* result = nullptr; grpc_slice bin; if (b64 == nullptr) return nullptr; - bin = grpc_base64_decode(b64, 1); + bin = grpc_base64_decode(exec_ctx, b64, 1); if (GRPC_SLICE_IS_EMPTY(bin)) { gpr_log(GPR_ERROR, "Invalid base64 for big num."); return nullptr; } result = BN_bin2bn(GRPC_SLICE_START_PTR(bin), TSI_SIZE_AS_SIZE(GRPC_SLICE_LENGTH(bin)), nullptr); - grpc_slice_unref_internal(bin); + grpc_slice_unref_internal(exec_ctx, bin); return result; } @@ -492,7 +495,8 @@ static int RSA_set0_key(RSA* r, BIGNUM* n, BIGNUM* e, BIGNUM* d) { } #endif // OPENSSL_VERSION_NUMBER < 0x10100000L -static EVP_PKEY* pkey_from_jwk(const grpc_json* json, const char* kty) { +static EVP_PKEY* pkey_from_jwk(grpc_exec_ctx* exec_ctx, const grpc_json* json, + const char* kty) { const grpc_json* key_prop; RSA* rsa = nullptr; EVP_PKEY* result = nullptr; @@ -511,10 +515,12 @@ static EVP_PKEY* pkey_from_jwk(const grpc_json* json, const char* kty) { } for (key_prop = json->child; key_prop != nullptr; key_prop = key_prop->next) { if (strcmp(key_prop->key, "n") == 0) { - tmp_n = bignum_from_base64(validate_string_field(key_prop, "n")); + tmp_n = + bignum_from_base64(exec_ctx, validate_string_field(key_prop, "n")); if (tmp_n == nullptr) goto end; } else if (strcmp(key_prop->key, "e") == 0) { - tmp_e = bignum_from_base64(validate_string_field(key_prop, "e")); + tmp_e = + bignum_from_base64(exec_ctx, validate_string_field(key_prop, "e")); if (tmp_e == nullptr) goto end; } } @@ -539,7 +545,8 @@ end: return result; } -static EVP_PKEY* find_verification_key(const grpc_json* json, +static EVP_PKEY* find_verification_key(grpc_exec_ctx* exec_ctx, + const grpc_json* json, const char* header_alg, const char* header_kid) { const grpc_json* jkey; @@ -584,7 +591,7 @@ static EVP_PKEY* find_verification_key(const grpc_json* json, } if (alg != nullptr && kid != nullptr && kty != nullptr && strcmp(kid, header_kid) == 0 && strcmp(alg, header_alg) == 0) { - return pkey_from_jwk(jkey, kty); + return pkey_from_jwk(exec_ctx, jkey, kty); } } gpr_log(GPR_ERROR, @@ -625,7 +632,8 @@ end: return result; } -static void on_keys_retrieved(void* user_data, grpc_error* error) { +static void on_keys_retrieved(grpc_exec_ctx* exec_ctx, void* user_data, + grpc_error* error) { verifier_cb_ctx* ctx = (verifier_cb_ctx*)user_data; grpc_json* json = json_from_http(&ctx->responses[HTTP_RESPONSE_KEYS]); EVP_PKEY* verification_key = nullptr; @@ -637,7 +645,7 @@ static void on_keys_retrieved(void* user_data, grpc_error* error) { goto end; } verification_key = - find_verification_key(json, ctx->header->alg, ctx->header->kid); + find_verification_key(exec_ctx, json, ctx->header->alg, ctx->header->kid); if (verification_key == nullptr) { gpr_log(GPR_ERROR, "Could not find verification key with kid %s.", ctx->header->kid); @@ -661,11 +669,12 @@ static void on_keys_retrieved(void* user_data, grpc_error* error) { end: if (json != nullptr) grpc_json_destroy(json); EVP_PKEY_free(verification_key); - ctx->user_cb(ctx->user_data, status, claims); - verifier_cb_ctx_destroy(ctx); + ctx->user_cb(exec_ctx, ctx->user_data, status, claims); + verifier_cb_ctx_destroy(exec_ctx, ctx); } -static void on_openid_config_retrieved(void* user_data, grpc_error* error) { +static void on_openid_config_retrieved(grpc_exec_ctx* exec_ctx, void* user_data, + grpc_error* error) { const grpc_json* cur; verifier_cb_ctx* ctx = (verifier_cb_ctx*)user_data; const grpc_http_response* response = &ctx->responses[HTTP_RESPONSE_OPENID]; @@ -702,19 +711,20 @@ static void on_openid_config_retrieved(void* user_data, grpc_error* error) { extreme memory pressure. */ resource_quota = grpc_resource_quota_create("jwt_verifier"); grpc_httpcli_get( - &ctx->verifier->http_ctx, &ctx->pollent, resource_quota, &req, - grpc_core::ExecCtx::Get()->Now() + grpc_jwt_verifier_max_delay, + exec_ctx, &ctx->verifier->http_ctx, &ctx->pollent, resource_quota, &req, + grpc_exec_ctx_now(exec_ctx) + grpc_jwt_verifier_max_delay, GRPC_CLOSURE_CREATE(on_keys_retrieved, ctx, grpc_schedule_on_exec_ctx), &ctx->responses[HTTP_RESPONSE_KEYS]); - grpc_resource_quota_unref_internal(resource_quota); + grpc_resource_quota_unref_internal(exec_ctx, resource_quota); grpc_json_destroy(json); gpr_free(req.host); return; error: if (json != nullptr) grpc_json_destroy(json); - ctx->user_cb(ctx->user_data, GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR, nullptr); - verifier_cb_ctx_destroy(ctx); + ctx->user_cb(exec_ctx, ctx->user_data, GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR, + nullptr); + verifier_cb_ctx_destroy(exec_ctx, ctx); } static email_key_mapping* verifier_get_mapping(grpc_jwt_verifier* v, @@ -762,7 +772,8 @@ const char* grpc_jwt_issuer_email_domain(const char* issuer) { } /* Takes ownership of ctx. */ -static void retrieve_key_and_verify(verifier_cb_ctx* ctx) { +static void retrieve_key_and_verify(grpc_exec_ctx* exec_ctx, + verifier_cb_ctx* ctx) { const char* email_domain; grpc_closure* http_cb; char* path_prefix = nullptr; @@ -829,21 +840,23 @@ static void retrieve_key_and_verify(verifier_cb_ctx* ctx) { channel. This would allow us to cancel an authentication query when under extreme memory pressure. */ resource_quota = grpc_resource_quota_create("jwt_verifier"); - grpc_httpcli_get( - &ctx->verifier->http_ctx, &ctx->pollent, resource_quota, &req, - grpc_core::ExecCtx::Get()->Now() + grpc_jwt_verifier_max_delay, http_cb, - &ctx->responses[rsp_idx]); - grpc_resource_quota_unref_internal(resource_quota); + grpc_httpcli_get(exec_ctx, &ctx->verifier->http_ctx, &ctx->pollent, + resource_quota, &req, + grpc_exec_ctx_now(exec_ctx) + grpc_jwt_verifier_max_delay, + http_cb, &ctx->responses[rsp_idx]); + grpc_resource_quota_unref_internal(exec_ctx, resource_quota); gpr_free(req.host); gpr_free(req.http.path); return; error: - ctx->user_cb(ctx->user_data, GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR, nullptr); - verifier_cb_ctx_destroy(ctx); + ctx->user_cb(exec_ctx, ctx->user_data, GRPC_JWT_VERIFIER_KEY_RETRIEVAL_ERROR, + nullptr); + verifier_cb_ctx_destroy(exec_ctx, ctx); } -void grpc_jwt_verifier_verify(grpc_jwt_verifier* verifier, +void grpc_jwt_verifier_verify(grpc_exec_ctx* exec_ctx, + grpc_jwt_verifier* verifier, grpc_pollset* pollset, const char* jwt, const char* audience, grpc_jwt_verification_done_cb cb, @@ -862,32 +875,35 @@ void grpc_jwt_verifier_verify(grpc_jwt_verifier* verifier, cb != nullptr); dot = strchr(cur, '.'); if (dot == nullptr) goto error; - json = parse_json_part_from_jwt(cur, (size_t)(dot - cur), &header_buffer); + json = parse_json_part_from_jwt(exec_ctx, cur, (size_t)(dot - cur), + &header_buffer); if (json == nullptr) goto error; - header = jose_header_from_json(json, header_buffer); + header = jose_header_from_json(exec_ctx, json, header_buffer); if (header == nullptr) goto error; cur = dot + 1; dot = strchr(cur, '.'); if (dot == nullptr) goto error; - json = parse_json_part_from_jwt(cur, (size_t)(dot - cur), &claims_buffer); + json = parse_json_part_from_jwt(exec_ctx, cur, (size_t)(dot - cur), + &claims_buffer); if (json == nullptr) goto error; - claims = grpc_jwt_claims_from_json(json, claims_buffer); + claims = grpc_jwt_claims_from_json(exec_ctx, json, claims_buffer); if (claims == nullptr) goto error; signed_jwt_len = (size_t)(dot - jwt); cur = dot + 1; - signature = grpc_base64_decode(cur, 1); + signature = grpc_base64_decode(exec_ctx, cur, 1); if (GRPC_SLICE_IS_EMPTY(signature)) goto error; retrieve_key_and_verify( + exec_ctx, verifier_cb_ctx_create(verifier, pollset, header, claims, audience, signature, jwt, signed_jwt_len, user_data, cb)); return; error: - if (header != nullptr) jose_header_destroy(header); - if (claims != nullptr) grpc_jwt_claims_destroy(claims); - cb(user_data, GRPC_JWT_VERIFIER_BAD_FORMAT, nullptr); + if (header != nullptr) jose_header_destroy(exec_ctx, header); + if (claims != nullptr) grpc_jwt_claims_destroy(exec_ctx, claims); + cb(exec_ctx, user_data, GRPC_JWT_VERIFIER_BAD_FORMAT, nullptr); } grpc_jwt_verifier* grpc_jwt_verifier_create( @@ -914,10 +930,10 @@ grpc_jwt_verifier* grpc_jwt_verifier_create( return v; } -void grpc_jwt_verifier_destroy(grpc_jwt_verifier* v) { +void grpc_jwt_verifier_destroy(grpc_exec_ctx* exec_ctx, grpc_jwt_verifier* v) { size_t i; if (v == nullptr) return; - grpc_httpcli_context_destroy(&v->http_ctx); + grpc_httpcli_context_destroy(exec_ctx, &v->http_ctx); if (v->mappings != nullptr) { for (i = 0; i < v->num_mappings; i++) { gpr_free(v->mappings[i].email_domain); |