diff options
Diffstat (limited to 'src/core/lib/security')
20 files changed, 798 insertions, 753 deletions
diff --git a/src/core/lib/security/credentials/credentials.h b/src/core/lib/security/credentials/credentials.h index 6fb5b5b15a..85b3bc5350 100644 --- a/src/core/lib/security/credentials/credentials.h +++ b/src/core/lib/security/credentials/credentials.h @@ -141,8 +141,8 @@ grpc_channel_credentials_duplicate_without_call_credentials( /* --- grpc_credentials_md. --- */ typedef struct { - gpr_slice key; - gpr_slice value; + grpc_slice key; + grpc_slice value; } grpc_credentials_md; typedef struct { @@ -157,7 +157,7 @@ grpc_credentials_md_store *grpc_credentials_md_store_create( /* Will ref key and value. */ void grpc_credentials_md_store_add(grpc_credentials_md_store *store, - gpr_slice key, gpr_slice value); + grpc_slice key, grpc_slice value); void grpc_credentials_md_store_add_cstrings(grpc_credentials_md_store *store, const char *key, const char *value); grpc_credentials_md_store *grpc_credentials_md_store_ref( diff --git a/src/core/lib/security/credentials/credentials_metadata.c b/src/core/lib/security/credentials/credentials_metadata.c index 6a352aab3a..e6cb567734 100644 --- a/src/core/lib/security/credentials/credentials_metadata.c +++ b/src/core/lib/security/credentials/credentials_metadata.c @@ -59,11 +59,11 @@ grpc_credentials_md_store *grpc_credentials_md_store_create( } void grpc_credentials_md_store_add(grpc_credentials_md_store *store, - gpr_slice key, gpr_slice value) { + grpc_slice key, grpc_slice value) { if (store == NULL) return; store_ensure_capacity(store); - store->entries[store->num_entries].key = gpr_slice_ref(key); - store->entries[store->num_entries].value = gpr_slice_ref(value); + store->entries[store->num_entries].key = grpc_slice_ref(key); + store->entries[store->num_entries].value = grpc_slice_ref(value); store->num_entries++; } @@ -72,9 +72,9 @@ void grpc_credentials_md_store_add_cstrings(grpc_credentials_md_store *store, const char *value) { if (store == NULL) return; store_ensure_capacity(store); - store->entries[store->num_entries].key = gpr_slice_from_copied_string(key); + store->entries[store->num_entries].key = grpc_slice_from_copied_string(key); store->entries[store->num_entries].value = - gpr_slice_from_copied_string(value); + grpc_slice_from_copied_string(value); store->num_entries++; } @@ -91,8 +91,8 @@ void grpc_credentials_md_store_unref(grpc_credentials_md_store *store) { if (store->entries != NULL) { size_t i; for (i = 0; i < store->num_entries; i++) { - gpr_slice_unref(store->entries[i].key); - gpr_slice_unref(store->entries[i].value); + grpc_slice_unref(store->entries[i].key); + grpc_slice_unref(store->entries[i].value); } gpr_free(store->entries); } diff --git a/src/core/lib/security/credentials/google_default/google_default_credentials.c b/src/core/lib/security/credentials/google_default/google_default_credentials.c index cb5ba554b0..afe0e3d357 100644 --- a/src/core/lib/security/credentials/google_default/google_default_credentials.c +++ b/src/core/lib/security/credentials/google_default/google_default_credentials.c @@ -45,6 +45,7 @@ #include "src/core/lib/iomgr/polling_entity.h" #include "src/core/lib/security/credentials/jwt/jwt_credentials.h" #include "src/core/lib/security/credentials/oauth2/oauth2_credentials.h" +#include "src/core/lib/slice/slice_string_helpers.h" #include "src/core/lib/support/env.h" #include "src/core/lib/support/string.h" #include "src/core/lib/surface/api_trace.h" @@ -174,7 +175,7 @@ static grpc_error *create_default_creds_from_path( grpc_auth_json_key key; grpc_auth_refresh_token token; grpc_call_credentials *result = NULL; - gpr_slice creds_data = gpr_empty_slice(); + grpc_slice creds_data = gpr_empty_slice(); grpc_error *error = GRPC_ERROR_NONE; if (creds_path == NULL) { error = GRPC_ERROR_CREATE("creds_path unset"); @@ -185,9 +186,9 @@ static grpc_error *create_default_creds_from_path( goto end; } json = grpc_json_parse_string_with_len( - (char *)GPR_SLICE_START_PTR(creds_data), GPR_SLICE_LENGTH(creds_data)); + (char *)GRPC_SLICE_START_PTR(creds_data), GRPC_SLICE_LENGTH(creds_data)); if (json == NULL) { - char *dump = gpr_dump_slice(creds_data, GPR_DUMP_HEX | GPR_DUMP_ASCII); + char *dump = grpc_dump_slice(creds_data, GPR_DUMP_HEX | GPR_DUMP_ASCII); error = grpc_error_set_str(GRPC_ERROR_CREATE("Failed to parse JSON"), GRPC_ERROR_STR_RAW_BYTES, dump); gpr_free(dump); @@ -224,7 +225,7 @@ static grpc_error *create_default_creds_from_path( end: GPR_ASSERT((result == NULL) + (error == GRPC_ERROR_NONE) == 1); if (creds_path != NULL) gpr_free(creds_path); - gpr_slice_unref(creds_data); + grpc_slice_unref(creds_data); if (json != NULL) grpc_json_destroy(json); *creds = result; return error; diff --git a/src/core/lib/security/credentials/jwt/json_token.h b/src/core/lib/security/credentials/jwt/json_token.h index 07fc5bf0e0..c13eb55803 100644 --- a/src/core/lib/security/credentials/jwt/json_token.h +++ b/src/core/lib/security/credentials/jwt/json_token.h @@ -34,7 +34,7 @@ #ifndef GRPC_CORE_LIB_SECURITY_CREDENTIALS_JWT_JSON_TOKEN_H #define GRPC_CORE_LIB_SECURITY_CREDENTIALS_JWT_JSON_TOKEN_H -#include <grpc/support/slice.h> +#include <grpc/slice.h> #include <openssl/rsa.h> #include "src/core/lib/json/json.h" diff --git a/src/core/lib/security/credentials/jwt/jwt_credentials.c b/src/core/lib/security/credentials/jwt/jwt_credentials.c index f87ba0ce8d..3daf0f4ef7 100644 --- a/src/core/lib/security/credentials/jwt/jwt_credentials.c +++ b/src/core/lib/security/credentials/jwt/jwt_credentials.c @@ -144,17 +144,44 @@ grpc_service_account_jwt_access_credentials_create_from_auth_json_key( return &c->base; } +static char *redact_private_key(const char *json_key) { + char *json_copy = gpr_strdup(json_key); + grpc_json *json = grpc_json_parse_string(json_copy); + if (!json) { + gpr_free(json_copy); + return gpr_strdup("<Json failed to parse.>"); + } + const char *redacted = "<redacted>"; + grpc_json *current = json->child; + while (current) { + if (current->type == GRPC_JSON_STRING && + strcmp(current->key, "private_key") == 0) { + current->value = (char *)redacted; + break; + } + current = current->next; + } + char *clean_json = grpc_json_dump_to_string(json, 2); + gpr_free(json_copy); + grpc_json_destroy(json); + return clean_json; +} + grpc_call_credentials *grpc_service_account_jwt_access_credentials_create( const char *json_key, gpr_timespec token_lifetime, void *reserved) { - GRPC_API_TRACE( - "grpc_service_account_jwt_access_credentials_create(" - "json_key=%s, " - "token_lifetime=" - "gpr_timespec { tv_sec: %" PRId64 - ", tv_nsec: %d, clock_type: %d }, " - "reserved=%p)", - 5, (json_key, token_lifetime.tv_sec, token_lifetime.tv_nsec, - (int)token_lifetime.clock_type, reserved)); + if (grpc_api_trace) { + char *clean_json = redact_private_key(json_key); + gpr_log(GPR_INFO, + "grpc_service_account_jwt_access_credentials_create(" + "json_key=%s, " + "token_lifetime=" + "gpr_timespec { tv_sec: %" PRId64 + ", tv_nsec: %d, clock_type: %d }, " + "reserved=%p)", + clean_json, token_lifetime.tv_sec, token_lifetime.tv_nsec, + (int)token_lifetime.clock_type, reserved); + gpr_free(clean_json); + } GPR_ASSERT(reserved == NULL); return grpc_service_account_jwt_access_credentials_create_from_auth_json_key( grpc_auth_json_key_create_from_string(json_key), token_lifetime); diff --git a/src/core/lib/security/credentials/jwt/jwt_verifier.c b/src/core/lib/security/credentials/jwt/jwt_verifier.c index 43eb642515..42bd89dd0a 100644 --- a/src/core/lib/security/credentials/jwt/jwt_verifier.c +++ b/src/core/lib/security/credentials/jwt/jwt_verifier.c @@ -85,18 +85,18 @@ 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, - gpr_slice *buffer) { + grpc_slice *buffer) { grpc_json *json; *buffer = grpc_base64_decode_with_len(str, len, 1); - if (GPR_SLICE_IS_EMPTY(*buffer)) { + if (GRPC_SLICE_IS_EMPTY(*buffer)) { gpr_log(GPR_ERROR, "Invalid base64."); return NULL; } - json = grpc_json_parse_string_with_len((char *)GPR_SLICE_START_PTR(*buffer), - GPR_SLICE_LENGTH(*buffer)); + json = grpc_json_parse_string_with_len((char *)GRPC_SLICE_START_PTR(*buffer), + GRPC_SLICE_LENGTH(*buffer)); if (json == NULL) { - gpr_slice_unref(*buffer); + grpc_slice_unref(*buffer); gpr_log(GPR_ERROR, "JSON parsing error."); } return json; @@ -129,16 +129,16 @@ typedef struct { const char *kid; const char *typ; /* TODO(jboeuf): Add others as needed (jku, jwk, x5u, x5c and so on...). */ - gpr_slice buffer; + grpc_slice buffer; } jose_header; static void jose_header_destroy(jose_header *h) { - gpr_slice_unref(h->buffer); + grpc_slice_unref(h->buffer); gpr_free(h); } /* Takes ownership of json and buffer. */ -static jose_header *jose_header_from_json(grpc_json *json, gpr_slice buffer) { +static jose_header *jose_header_from_json(grpc_json *json, grpc_slice buffer) { grpc_json *cur; jose_header *h = gpr_malloc(sizeof(jose_header)); memset(h, 0, sizeof(jose_header)); @@ -190,12 +190,12 @@ struct grpc_jwt_claims { gpr_timespec nbf; grpc_json *json; - gpr_slice buffer; + grpc_slice buffer; }; void grpc_jwt_claims_destroy(grpc_jwt_claims *claims) { grpc_json_destroy(claims->json); - gpr_slice_unref(claims->buffer); + grpc_slice_unref(claims->buffer); gpr_free(claims); } @@ -240,7 +240,7 @@ 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, gpr_slice buffer) { +grpc_jwt_claims *grpc_jwt_claims_from_json(grpc_json *json, grpc_slice buffer) { grpc_json *cur; grpc_jwt_claims *claims = gpr_malloc(sizeof(grpc_jwt_claims)); memset(claims, 0, sizeof(grpc_jwt_claims)); @@ -333,8 +333,8 @@ typedef struct { jose_header *header; grpc_jwt_claims *claims; char *audience; - gpr_slice signature; - gpr_slice signed_data; + grpc_slice signature; + grpc_slice signed_data; void *user_data; grpc_jwt_verification_done_cb user_cb; grpc_http_response responses[HTTP_RESPONSE_COUNT]; @@ -343,7 +343,7 @@ typedef struct { /* Takes ownership of the header, claims and signature. */ 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, gpr_slice signature, + 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_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; @@ -355,7 +355,7 @@ static verifier_cb_ctx *verifier_cb_ctx_create( ctx->audience = gpr_strdup(audience); ctx->claims = claims; ctx->signature = signature; - ctx->signed_data = gpr_slice_from_copied_buffer(signed_jwt, signed_jwt_len); + 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); @@ -365,8 +365,8 @@ static verifier_cb_ctx *verifier_cb_ctx_create( void verifier_cb_ctx_destroy(verifier_cb_ctx *ctx) { if (ctx->audience != NULL) gpr_free(ctx->audience); if (ctx->claims != NULL) grpc_jwt_claims_destroy(ctx->claims); - gpr_slice_unref(ctx->signature); - gpr_slice_unref(ctx->signed_data); + grpc_slice_unref(ctx->signature); + grpc_slice_unref(ctx->signed_data); jose_header_destroy(ctx->header); for (size_t i = 0; i < HTTP_RESPONSE_COUNT; i++) { grpc_http_response_destroy(&ctx->responses[i]); @@ -449,17 +449,17 @@ end: static BIGNUM *bignum_from_base64(const char *b64) { BIGNUM *result = NULL; - gpr_slice bin; + grpc_slice bin; if (b64 == NULL) return NULL; bin = grpc_base64_decode(b64, 1); - if (GPR_SLICE_IS_EMPTY(bin)) { + if (GRPC_SLICE_IS_EMPTY(bin)) { gpr_log(GPR_ERROR, "Invalid base64 for big num."); return NULL; } - result = BN_bin2bn(GPR_SLICE_START_PTR(bin), - TSI_SIZE_AS_SIZE(GPR_SLICE_LENGTH(bin)), NULL); - gpr_slice_unref(bin); + result = BN_bin2bn(GRPC_SLICE_START_PTR(bin), + TSI_SIZE_AS_SIZE(GRPC_SLICE_LENGTH(bin)), NULL); + grpc_slice_unref(bin); return result; } @@ -553,7 +553,7 @@ static EVP_PKEY *find_verification_key(const grpc_json *json, } static int verify_jwt_signature(EVP_PKEY *key, const char *alg, - gpr_slice signature, gpr_slice signed_data) { + grpc_slice signature, grpc_slice signed_data) { EVP_MD_CTX *md_ctx = EVP_MD_CTX_create(); const EVP_MD *md = evp_md_from_alg(alg); int result = 0; @@ -567,13 +567,13 @@ static int verify_jwt_signature(EVP_PKEY *key, const char *alg, gpr_log(GPR_ERROR, "EVP_DigestVerifyInit failed."); goto end; } - if (EVP_DigestVerifyUpdate(md_ctx, GPR_SLICE_START_PTR(signed_data), - GPR_SLICE_LENGTH(signed_data)) != 1) { + if (EVP_DigestVerifyUpdate(md_ctx, GRPC_SLICE_START_PTR(signed_data), + GRPC_SLICE_LENGTH(signed_data)) != 1) { gpr_log(GPR_ERROR, "EVP_DigestVerifyUpdate failed."); goto end; } - if (EVP_DigestVerifyFinal(md_ctx, GPR_SLICE_START_PTR(signature), - GPR_SLICE_LENGTH(signature)) != 1) { + if (EVP_DigestVerifyFinal(md_ctx, GRPC_SLICE_START_PTR(signature), + GRPC_SLICE_LENGTH(signature)) != 1) { gpr_log(GPR_ERROR, "JWT signature verification failed."); goto end; } @@ -799,9 +799,9 @@ void grpc_jwt_verifier_verify(grpc_exec_ctx *exec_ctx, grpc_json *json; jose_header *header = NULL; grpc_jwt_claims *claims = NULL; - gpr_slice header_buffer; - gpr_slice claims_buffer; - gpr_slice signature; + grpc_slice header_buffer; + grpc_slice claims_buffer; + grpc_slice signature; size_t signed_jwt_len; const char *cur = jwt; @@ -824,7 +824,7 @@ void grpc_jwt_verifier_verify(grpc_exec_ctx *exec_ctx, signed_jwt_len = (size_t)(dot - jwt); cur = dot + 1; signature = grpc_base64_decode(cur, 1); - if (GPR_SLICE_IS_EMPTY(signature)) goto error; + if (GRPC_SLICE_IS_EMPTY(signature)) goto error; retrieve_key_and_verify( exec_ctx, verifier_cb_ctx_create(verifier, pollset, header, claims, audience, diff --git a/src/core/lib/security/credentials/jwt/jwt_verifier.h b/src/core/lib/security/credentials/jwt/jwt_verifier.h index b0f6d1c240..f09f9d5d47 100644 --- a/src/core/lib/security/credentials/jwt/jwt_verifier.h +++ b/src/core/lib/security/credentials/jwt/jwt_verifier.h @@ -37,7 +37,7 @@ #include "src/core/lib/iomgr/pollset.h" #include "src/core/lib/json/json.h" -#include <grpc/support/slice.h> +#include <grpc/slice.h> #include <grpc/support/time.h> /* --- Constants. --- */ @@ -129,7 +129,7 @@ void grpc_jwt_verifier_verify(grpc_exec_ctx *exec_ctx, /* --- TESTING ONLY exposed functions. --- */ -grpc_jwt_claims *grpc_jwt_claims_from_json(grpc_json *json, gpr_slice buffer); +grpc_jwt_claims *grpc_jwt_claims_from_json(grpc_json *json, grpc_slice buffer); grpc_jwt_verifier_status grpc_jwt_claims_check(const grpc_jwt_claims *claims, const char *audience); diff --git a/src/core/lib/security/credentials/oauth2/oauth2_credentials.c b/src/core/lib/security/credentials/oauth2/oauth2_credentials.c index d980577c46..b3625b22c0 100644 --- a/src/core/lib/security/credentials/oauth2/oauth2_credentials.c +++ b/src/core/lib/security/credentials/oauth2/oauth2_credentials.c @@ -392,15 +392,32 @@ grpc_refresh_token_credentials_create_from_auth_refresh_token( return &c->base.base; } +static char *create_loggable_refresh_token(grpc_auth_refresh_token *token) { + if (strcmp(token->type, GRPC_AUTH_JSON_TYPE_INVALID) == 0) { + return gpr_strdup("<Invalid json token>"); + } + char *loggable_token = NULL; + gpr_asprintf(&loggable_token, + "{\n type: %s\n client_id: %s\n client_secret: " + "<redacted>\n refresh_token: <redacted>\n}", + token->type, token->client_id); + return loggable_token; +} + grpc_call_credentials *grpc_google_refresh_token_credentials_create( const char *json_refresh_token, void *reserved) { - GRPC_API_TRACE( - "grpc_refresh_token_credentials_create(json_refresh_token=%s, " - "reserved=%p)", - 2, (json_refresh_token, reserved)); + grpc_auth_refresh_token token = + grpc_auth_refresh_token_create_from_string(json_refresh_token); + if (grpc_api_trace) { + char *loggable_token = create_loggable_refresh_token(&token); + gpr_log(GPR_INFO, + "grpc_refresh_token_credentials_create(json_refresh_token=%s, " + "reserved=%p)", + loggable_token, reserved); + gpr_free(loggable_token); + } GPR_ASSERT(reserved == NULL); - return grpc_refresh_token_credentials_create_from_auth_refresh_token( - grpc_auth_refresh_token_create_from_string(json_refresh_token)); + return grpc_refresh_token_credentials_create_from_auth_refresh_token(token); } // @@ -430,9 +447,9 @@ grpc_call_credentials *grpc_access_token_credentials_create( gpr_malloc(sizeof(grpc_access_token_credentials)); char *token_md_value; GRPC_API_TRACE( - "grpc_access_token_credentials_create(access_token=%s, " + "grpc_access_token_credentials_create(access_token=<redacted>, " "reserved=%p)", - 2, (access_token, reserved)); + 1, (reserved)); GPR_ASSERT(reserved == NULL); memset(c, 0, sizeof(grpc_access_token_credentials)); c->base.type = GRPC_CALL_CREDENTIALS_TYPE_OAUTH2; diff --git a/src/core/lib/security/credentials/plugin/plugin_credentials.c b/src/core/lib/security/credentials/plugin/plugin_credentials.c index 905de3723e..5d950098a0 100644 --- a/src/core/lib/security/credentials/plugin/plugin_credentials.c +++ b/src/core/lib/security/credentials/plugin/plugin_credentials.c @@ -93,17 +93,19 @@ static void plugin_md_request_metadata_ready(void *request, } else if (num_md > 0) { md_array = gpr_malloc(num_md * sizeof(grpc_credentials_md)); for (i = 0; i < num_md; i++) { - md_array[i].key = gpr_slice_from_copied_string(md[i].key); + md_array[i].key = grpc_slice_from_copied_string(md[i].key); md_array[i].value = - gpr_slice_from_copied_buffer(md[i].value, md[i].value_length); + grpc_slice_from_copied_buffer(md[i].value, md[i].value_length); } r->cb(&exec_ctx, r->user_data, md_array, num_md, GRPC_CREDENTIALS_OK, NULL); for (i = 0; i < num_md; i++) { - gpr_slice_unref(md_array[i].key); - gpr_slice_unref(md_array[i].value); + grpc_slice_unref(md_array[i].key); + grpc_slice_unref(md_array[i].value); } gpr_free(md_array); + } else if (num_md == 0) { + r->cb(&exec_ctx, r->user_data, NULL, 0, GRPC_CREDENTIALS_OK, NULL); } } gpr_free(r); diff --git a/src/core/lib/security/transport/client_auth_filter.c b/src/core/lib/security/transport/client_auth_filter.c index b366d1410f..053bf5972c 100644 --- a/src/core/lib/security/transport/client_auth_filter.c +++ b/src/core/lib/security/transport/client_auth_filter.c @@ -92,7 +92,7 @@ static void bubble_up_error(grpc_exec_ctx *exec_ctx, grpc_call_element *elem, grpc_status_code status, const char *error_msg) { call_data *calld = elem->call_data; gpr_log(GPR_ERROR, "Client side authentication failure: %s", error_msg); - gpr_slice error_slice = gpr_slice_from_copied_string(error_msg); + grpc_slice error_slice = grpc_slice_from_copied_string(error_msg); grpc_transport_stream_op_add_close(&calld->op, status, &error_slice); grpc_call_next_op(exec_ctx, elem, &calld->op); } @@ -121,8 +121,8 @@ static void on_credentials_metadata(grpc_exec_ctx *exec_ctx, void *user_data, for (i = 0; i < num_md; i++) { grpc_metadata_batch_add_tail( mdb, &calld->md_links[i], - grpc_mdelem_from_slices(gpr_slice_ref(md_elems[i].key), - gpr_slice_ref(md_elems[i].value))); + grpc_mdelem_from_slices(grpc_slice_ref(md_elems[i].key), + grpc_slice_ref(md_elems[i].value))); } grpc_call_next_op(exec_ctx, elem, op); } @@ -341,14 +341,8 @@ static void destroy_channel_elem(grpc_exec_ctx *exec_ctx, GRPC_AUTH_CONTEXT_UNREF(chand->auth_context, "client_auth_filter"); } -const grpc_channel_filter grpc_client_auth_filter = {auth_start_transport_op, - grpc_channel_next_op, - sizeof(call_data), - init_call_elem, - set_pollset_or_pollset_set, - destroy_call_elem, - sizeof(channel_data), - init_channel_elem, - destroy_channel_elem, - grpc_call_next_get_peer, - "client-auth"}; +const grpc_channel_filter grpc_client_auth_filter = { + auth_start_transport_op, grpc_channel_next_op, sizeof(call_data), + init_call_elem, set_pollset_or_pollset_set, destroy_call_elem, + sizeof(channel_data), init_channel_elem, destroy_channel_elem, + grpc_call_next_get_peer, grpc_channel_next_get_info, "client-auth"}; diff --git a/src/core/lib/security/transport/handshake.c b/src/core/lib/security/transport/handshake.c deleted file mode 100644 index fbeec312b6..0000000000 --- a/src/core/lib/security/transport/handshake.c +++ /dev/null @@ -1,374 +0,0 @@ -/* - * - * Copyright 2015, Google Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "src/core/lib/security/transport/handshake.h" - -#include <stdbool.h> -#include <string.h> - -#include <grpc/support/alloc.h> -#include <grpc/support/log.h> -#include <grpc/support/slice_buffer.h> -#include "src/core/lib/iomgr/timer.h" -#include "src/core/lib/security/context/security_context.h" -#include "src/core/lib/security/transport/secure_endpoint.h" -#include "src/core/lib/security/transport/tsi_error.h" - -#define GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE 256 - -typedef struct { - grpc_security_connector *connector; - tsi_handshaker *handshaker; - bool is_client_side; - unsigned char *handshake_buffer; - size_t handshake_buffer_size; - grpc_endpoint *wrapped_endpoint; - grpc_endpoint *secure_endpoint; - gpr_slice_buffer left_overs; - gpr_slice_buffer incoming; - gpr_slice_buffer outgoing; - grpc_security_handshake_done_cb cb; - void *user_data; - grpc_closure on_handshake_data_sent_to_peer; - grpc_closure on_handshake_data_received_from_peer; - grpc_auth_context *auth_context; - grpc_timer timer; - gpr_refcount refs; -} grpc_security_handshake; - -static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx, - void *setup, - grpc_error *error); - -static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx, void *setup, - grpc_error *error); - -static void security_connector_remove_handshake(grpc_security_handshake *h) { - GPR_ASSERT(!h->is_client_side); - grpc_security_connector_handshake_list *node; - grpc_security_connector_handshake_list *tmp; - grpc_server_security_connector *sc = - (grpc_server_security_connector *)h->connector; - gpr_mu_lock(&sc->mu); - node = sc->handshaking_handshakes; - if (node && node->handshake == h) { - sc->handshaking_handshakes = node->next; - gpr_free(node); - gpr_mu_unlock(&sc->mu); - return; - } - while (node) { - if (node->next->handshake == h) { - tmp = node->next; - node->next = node->next->next; - gpr_free(tmp); - gpr_mu_unlock(&sc->mu); - return; - } - node = node->next; - } - gpr_mu_unlock(&sc->mu); -} - -static void unref_handshake(grpc_security_handshake *h) { - if (gpr_unref(&h->refs)) { - if (h->handshaker != NULL) tsi_handshaker_destroy(h->handshaker); - if (h->handshake_buffer != NULL) gpr_free(h->handshake_buffer); - gpr_slice_buffer_destroy(&h->left_overs); - gpr_slice_buffer_destroy(&h->outgoing); - gpr_slice_buffer_destroy(&h->incoming); - GRPC_AUTH_CONTEXT_UNREF(h->auth_context, "handshake"); - GRPC_SECURITY_CONNECTOR_UNREF(h->connector, "handshake"); - gpr_free(h); - } -} - -static void security_handshake_done(grpc_exec_ctx *exec_ctx, - grpc_security_handshake *h, - grpc_error *error) { - grpc_timer_cancel(exec_ctx, &h->timer); - if (!h->is_client_side) { - security_connector_remove_handshake(h); - } - if (error == GRPC_ERROR_NONE) { - h->cb(exec_ctx, h->user_data, GRPC_SECURITY_OK, h->secure_endpoint, - h->auth_context); - } else { - const char *msg = grpc_error_string(error); - gpr_log(GPR_ERROR, "Security handshake failed: %s", msg); - grpc_error_free_string(msg); - - if (h->secure_endpoint != NULL) { - grpc_endpoint_shutdown(exec_ctx, h->secure_endpoint); - grpc_endpoint_destroy(exec_ctx, h->secure_endpoint); - } else { - grpc_endpoint_destroy(exec_ctx, h->wrapped_endpoint); - } - h->cb(exec_ctx, h->user_data, GRPC_SECURITY_ERROR, NULL, NULL); - } - unref_handshake(h); - GRPC_ERROR_UNREF(error); -} - -static void on_peer_checked(grpc_exec_ctx *exec_ctx, void *user_data, - grpc_security_status status, - grpc_auth_context *auth_context) { - grpc_security_handshake *h = user_data; - tsi_frame_protector *protector; - tsi_result result; - if (status != GRPC_SECURITY_OK) { - security_handshake_done( - exec_ctx, h, - grpc_error_set_int(GRPC_ERROR_CREATE("Error checking peer."), - GRPC_ERROR_INT_SECURITY_STATUS, status)); - return; - } - h->auth_context = GRPC_AUTH_CONTEXT_REF(auth_context, "handshake"); - result = - tsi_handshaker_create_frame_protector(h->handshaker, NULL, &protector); - if (result != TSI_OK) { - security_handshake_done( - exec_ctx, h, - grpc_set_tsi_error_result( - GRPC_ERROR_CREATE("Frame protector creation failed"), result)); - return; - } - h->secure_endpoint = - grpc_secure_endpoint_create(protector, h->wrapped_endpoint, - h->left_overs.slices, h->left_overs.count); - h->left_overs.count = 0; - h->left_overs.length = 0; - security_handshake_done(exec_ctx, h, GRPC_ERROR_NONE); - return; -} - -static void check_peer(grpc_exec_ctx *exec_ctx, grpc_security_handshake *h) { - tsi_peer peer; - tsi_result result = tsi_handshaker_extract_peer(h->handshaker, &peer); - - if (result != TSI_OK) { - security_handshake_done( - exec_ctx, h, grpc_set_tsi_error_result( - GRPC_ERROR_CREATE("Peer extraction failed"), result)); - return; - } - grpc_security_connector_check_peer(exec_ctx, h->connector, peer, - on_peer_checked, h); -} - -static void send_handshake_bytes_to_peer(grpc_exec_ctx *exec_ctx, - grpc_security_handshake *h) { - size_t offset = 0; - tsi_result result = TSI_OK; - gpr_slice to_send; - - do { - size_t to_send_size = h->handshake_buffer_size - offset; - result = tsi_handshaker_get_bytes_to_send_to_peer( - h->handshaker, h->handshake_buffer + offset, &to_send_size); - offset += to_send_size; - if (result == TSI_INCOMPLETE_DATA) { - h->handshake_buffer_size *= 2; - h->handshake_buffer = - gpr_realloc(h->handshake_buffer, h->handshake_buffer_size); - } - } while (result == TSI_INCOMPLETE_DATA); - - if (result != TSI_OK) { - security_handshake_done(exec_ctx, h, - grpc_set_tsi_error_result( - GRPC_ERROR_CREATE("Handshake failed"), result)); - return; - } - - to_send = - gpr_slice_from_copied_buffer((const char *)h->handshake_buffer, offset); - gpr_slice_buffer_reset_and_unref(&h->outgoing); - gpr_slice_buffer_add(&h->outgoing, to_send); - /* TODO(klempner,jboeuf): This should probably use the client setup - deadline */ - grpc_endpoint_write(exec_ctx, h->wrapped_endpoint, &h->outgoing, - &h->on_handshake_data_sent_to_peer); -} - -static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx, - void *handshake, - grpc_error *error) { - grpc_security_handshake *h = handshake; - size_t consumed_slice_size = 0; - tsi_result result = TSI_OK; - size_t i; - size_t num_left_overs; - int has_left_overs_in_current_slice = 0; - - if (error != GRPC_ERROR_NONE) { - security_handshake_done( - exec_ctx, h, - GRPC_ERROR_CREATE_REFERENCING("Handshake read failed", &error, 1)); - return; - } - - for (i = 0; i < h->incoming.count; i++) { - consumed_slice_size = GPR_SLICE_LENGTH(h->incoming.slices[i]); - result = tsi_handshaker_process_bytes_from_peer( - h->handshaker, GPR_SLICE_START_PTR(h->incoming.slices[i]), - &consumed_slice_size); - if (!tsi_handshaker_is_in_progress(h->handshaker)) break; - } - - if (tsi_handshaker_is_in_progress(h->handshaker)) { - /* We may need more data. */ - if (result == TSI_INCOMPLETE_DATA) { - grpc_endpoint_read(exec_ctx, h->wrapped_endpoint, &h->incoming, - &h->on_handshake_data_received_from_peer); - return; - } else { - send_handshake_bytes_to_peer(exec_ctx, h); - return; - } - } - - if (result != TSI_OK) { - security_handshake_done(exec_ctx, h, - grpc_set_tsi_error_result( - GRPC_ERROR_CREATE("Handshake failed"), result)); - return; - } - - /* Handshake is done and successful this point. */ - has_left_overs_in_current_slice = - (consumed_slice_size < GPR_SLICE_LENGTH(h->incoming.slices[i])); - num_left_overs = - (has_left_overs_in_current_slice ? 1 : 0) + h->incoming.count - i - 1; - if (num_left_overs == 0) { - check_peer(exec_ctx, h); - return; - } - - /* Put the leftovers in our buffer (ownership transfered). */ - if (has_left_overs_in_current_slice) { - gpr_slice_buffer_add( - &h->left_overs, - gpr_slice_split_tail(&h->incoming.slices[i], consumed_slice_size)); - gpr_slice_unref( - h->incoming.slices[i]); /* split_tail above increments refcount. */ - } - gpr_slice_buffer_addn( - &h->left_overs, &h->incoming.slices[i + 1], - num_left_overs - (size_t)has_left_overs_in_current_slice); - check_peer(exec_ctx, h); -} - -/* If handshake is NULL, the handshake is done. */ -static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx, - void *handshake, grpc_error *error) { - grpc_security_handshake *h = handshake; - - /* Make sure that write is OK. */ - if (error != GRPC_ERROR_NONE) { - if (handshake != NULL) - security_handshake_done( - exec_ctx, h, - GRPC_ERROR_CREATE_REFERENCING("Handshake write failed", &error, 1)); - return; - } - - /* We may be done. */ - if (tsi_handshaker_is_in_progress(h->handshaker)) { - /* TODO(klempner,jboeuf): This should probably use the client setup - deadline */ - grpc_endpoint_read(exec_ctx, h->wrapped_endpoint, &h->incoming, - &h->on_handshake_data_received_from_peer); - } else { - check_peer(exec_ctx, h); - } -} - -static void on_timeout(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { - grpc_security_handshake *h = arg; - if (error == GRPC_ERROR_NONE) { - grpc_endpoint_shutdown(exec_ctx, h->wrapped_endpoint); - } - unref_handshake(h); -} - -void grpc_do_security_handshake( - grpc_exec_ctx *exec_ctx, tsi_handshaker *handshaker, - grpc_security_connector *connector, bool is_client_side, - grpc_endpoint *nonsecure_endpoint, gpr_slice_buffer *read_buffer, - gpr_timespec deadline, grpc_security_handshake_done_cb cb, - void *user_data) { - grpc_security_connector_handshake_list *handshake_node; - grpc_security_handshake *h = gpr_malloc(sizeof(grpc_security_handshake)); - memset(h, 0, sizeof(grpc_security_handshake)); - h->handshaker = handshaker; - h->connector = GRPC_SECURITY_CONNECTOR_REF(connector, "handshake"); - h->is_client_side = is_client_side; - h->handshake_buffer_size = GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE; - h->handshake_buffer = gpr_malloc(h->handshake_buffer_size); - h->wrapped_endpoint = nonsecure_endpoint; - h->user_data = user_data; - h->cb = cb; - gpr_ref_init(&h->refs, 2); /* timer and handshake proper each get a ref */ - grpc_closure_init(&h->on_handshake_data_sent_to_peer, - on_handshake_data_sent_to_peer, h); - grpc_closure_init(&h->on_handshake_data_received_from_peer, - on_handshake_data_received_from_peer, h); - gpr_slice_buffer_init(&h->left_overs); - gpr_slice_buffer_init(&h->outgoing); - gpr_slice_buffer_init(&h->incoming); - if (read_buffer != NULL) { - gpr_slice_buffer_move_into(read_buffer, &h->incoming); - gpr_free(read_buffer); - } - if (!is_client_side) { - grpc_server_security_connector *server_connector = - (grpc_server_security_connector *)connector; - handshake_node = gpr_malloc(sizeof(grpc_security_connector_handshake_list)); - handshake_node->handshake = h; - gpr_mu_lock(&server_connector->mu); - handshake_node->next = server_connector->handshaking_handshakes; - server_connector->handshaking_handshakes = handshake_node; - gpr_mu_unlock(&server_connector->mu); - } - send_handshake_bytes_to_peer(exec_ctx, h); - grpc_timer_init(exec_ctx, &h->timer, - gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC), - on_timeout, h, gpr_now(GPR_CLOCK_MONOTONIC)); -} - -void grpc_security_handshake_shutdown(grpc_exec_ctx *exec_ctx, - void *handshake) { - grpc_security_handshake *h = handshake; - grpc_endpoint_shutdown(exec_ctx, h->wrapped_endpoint); -} diff --git a/src/core/lib/security/transport/secure_endpoint.c b/src/core/lib/security/transport/secure_endpoint.c index 3924997d31..1b278410e8 100644 --- a/src/core/lib/security/transport/secure_endpoint.c +++ b/src/core/lib/security/transport/secure_endpoint.c @@ -31,15 +31,22 @@ * */ -#include "src/core/lib/security/transport/secure_endpoint.h" +/* With the addition of a libuv endpoint, sockaddr.h now includes uv.h when + using that endpoint. Because of various transitive includes in uv.h, + including windows.h on Windows, uv.h must be included before other system + headers. Therefore, sockaddr.h must always be included first */ +#include "src/core/lib/iomgr/sockaddr.h" + +#include <grpc/slice.h> +#include <grpc/slice_buffer.h> #include <grpc/support/alloc.h> #include <grpc/support/log.h> -#include <grpc/support/slice.h> -#include <grpc/support/slice_buffer.h> #include <grpc/support/sync.h> #include "src/core/lib/debug/trace.h" #include "src/core/lib/profiling/timers.h" +#include "src/core/lib/security/transport/secure_endpoint.h" #include "src/core/lib/security/transport/tsi_error.h" +#include "src/core/lib/slice/slice_string_helpers.h" #include "src/core/lib/support/string.h" #include "src/core/lib/tsi/transport_security_interface.h" @@ -54,15 +61,15 @@ typedef struct { grpc_closure *read_cb; grpc_closure *write_cb; grpc_closure on_read; - gpr_slice_buffer *read_buffer; - gpr_slice_buffer source_buffer; + grpc_slice_buffer *read_buffer; + grpc_slice_buffer source_buffer; /* saved handshaker leftover data to unprotect. */ - gpr_slice_buffer leftover_bytes; + grpc_slice_buffer leftover_bytes; /* buffers for read and write */ - gpr_slice read_staging_buffer; + grpc_slice read_staging_buffer; - gpr_slice write_staging_buffer; - gpr_slice_buffer output_buffer; + grpc_slice write_staging_buffer; + grpc_slice_buffer output_buffer; gpr_refcount ref; } secure_endpoint; @@ -73,11 +80,11 @@ static void destroy(grpc_exec_ctx *exec_ctx, secure_endpoint *secure_ep) { secure_endpoint *ep = secure_ep; grpc_endpoint_destroy(exec_ctx, ep->wrapped_ep); tsi_frame_protector_destroy(ep->protector); - gpr_slice_buffer_destroy(&ep->leftover_bytes); - gpr_slice_unref(ep->read_staging_buffer); - gpr_slice_unref(ep->write_staging_buffer); - gpr_slice_buffer_destroy(&ep->output_buffer); - gpr_slice_buffer_destroy(&ep->source_buffer); + grpc_slice_buffer_destroy(&ep->leftover_bytes); + grpc_slice_unref(ep->read_staging_buffer); + grpc_slice_unref(ep->write_staging_buffer); + grpc_slice_buffer_destroy(&ep->output_buffer); + grpc_slice_buffer_destroy(&ep->source_buffer); gpr_mu_destroy(&ep->protector_mu); gpr_free(ep); } @@ -121,10 +128,10 @@ static void secure_endpoint_ref(secure_endpoint *ep) { gpr_ref(&ep->ref); } static void flush_read_staging_buffer(secure_endpoint *ep, uint8_t **cur, uint8_t **end) { - gpr_slice_buffer_add(ep->read_buffer, ep->read_staging_buffer); - ep->read_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE); - *cur = GPR_SLICE_START_PTR(ep->read_staging_buffer); - *end = GPR_SLICE_END_PTR(ep->read_staging_buffer); + grpc_slice_buffer_add(ep->read_buffer, ep->read_staging_buffer); + ep->read_staging_buffer = grpc_slice_malloc(STAGING_BUFFER_SIZE); + *cur = GRPC_SLICE_START_PTR(ep->read_staging_buffer); + *end = GRPC_SLICE_END_PTR(ep->read_staging_buffer); } static void call_read_cb(grpc_exec_ctx *exec_ctx, secure_endpoint *ep, @@ -132,8 +139,8 @@ static void call_read_cb(grpc_exec_ctx *exec_ctx, secure_endpoint *ep, if (grpc_trace_secure_endpoint) { size_t i; for (i = 0; i < ep->read_buffer->count; i++) { - char *data = gpr_dump_slice(ep->read_buffer->slices[i], - GPR_DUMP_HEX | GPR_DUMP_ASCII); + char *data = grpc_dump_slice(ep->read_buffer->slices[i], + GPR_DUMP_HEX | GPR_DUMP_ASCII); gpr_log(GPR_DEBUG, "READ %p: %s", ep, data); gpr_free(data); } @@ -149,11 +156,11 @@ static void on_read(grpc_exec_ctx *exec_ctx, void *user_data, uint8_t keep_looping = 0; tsi_result result = TSI_OK; secure_endpoint *ep = (secure_endpoint *)user_data; - uint8_t *cur = GPR_SLICE_START_PTR(ep->read_staging_buffer); - uint8_t *end = GPR_SLICE_END_PTR(ep->read_staging_buffer); + uint8_t *cur = GRPC_SLICE_START_PTR(ep->read_staging_buffer); + uint8_t *end = GRPC_SLICE_END_PTR(ep->read_staging_buffer); if (error != GRPC_ERROR_NONE) { - gpr_slice_buffer_reset_and_unref(ep->read_buffer); + grpc_slice_buffer_reset_and_unref(ep->read_buffer); call_read_cb(exec_ctx, ep, GRPC_ERROR_CREATE_REFERENCING( "Secure read failed", &error, 1)); return; @@ -161,9 +168,9 @@ static void on_read(grpc_exec_ctx *exec_ctx, void *user_data, /* TODO(yangg) check error, maybe bail out early */ for (i = 0; i < ep->source_buffer.count; i++) { - gpr_slice encrypted = ep->source_buffer.slices[i]; - uint8_t *message_bytes = GPR_SLICE_START_PTR(encrypted); - size_t message_size = GPR_SLICE_LENGTH(encrypted); + grpc_slice encrypted = ep->source_buffer.slices[i]; + uint8_t *message_bytes = GRPC_SLICE_START_PTR(encrypted); + size_t message_size = GRPC_SLICE_LENGTH(encrypted); while (message_size > 0 || keep_looping) { size_t unprotected_buffer_size_written = (size_t)(end - cur); @@ -198,20 +205,20 @@ static void on_read(grpc_exec_ctx *exec_ctx, void *user_data, if (result != TSI_OK) break; } - if (cur != GPR_SLICE_START_PTR(ep->read_staging_buffer)) { - gpr_slice_buffer_add( + if (cur != GRPC_SLICE_START_PTR(ep->read_staging_buffer)) { + grpc_slice_buffer_add( ep->read_buffer, - gpr_slice_split_head( + grpc_slice_split_head( &ep->read_staging_buffer, - (size_t)(cur - GPR_SLICE_START_PTR(ep->read_staging_buffer)))); + (size_t)(cur - GRPC_SLICE_START_PTR(ep->read_staging_buffer)))); } /* TODO(yangg) experiment with moving this block after read_cb to see if it helps latency */ - gpr_slice_buffer_reset_and_unref(&ep->source_buffer); + grpc_slice_buffer_reset_and_unref(&ep->source_buffer); if (result != TSI_OK) { - gpr_slice_buffer_reset_and_unref(ep->read_buffer); + grpc_slice_buffer_reset_and_unref(ep->read_buffer); call_read_cb(exec_ctx, ep, grpc_set_tsi_error_result( GRPC_ERROR_CREATE("Unwrap failed"), result)); return; @@ -221,15 +228,15 @@ static void on_read(grpc_exec_ctx *exec_ctx, void *user_data, } static void endpoint_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *secure_ep, - gpr_slice_buffer *slices, grpc_closure *cb) { + grpc_slice_buffer *slices, grpc_closure *cb) { secure_endpoint *ep = (secure_endpoint *)secure_ep; ep->read_cb = cb; ep->read_buffer = slices; - gpr_slice_buffer_reset_and_unref(ep->read_buffer); + grpc_slice_buffer_reset_and_unref(ep->read_buffer); SECURE_ENDPOINT_REF(ep, "read"); if (ep->leftover_bytes.count) { - gpr_slice_buffer_swap(&ep->leftover_bytes, &ep->source_buffer); + grpc_slice_buffer_swap(&ep->leftover_bytes, &ep->source_buffer); GPR_ASSERT(ep->leftover_bytes.count == 0); on_read(exec_ctx, ep, GRPC_ERROR_NONE); return; @@ -241,37 +248,37 @@ static void endpoint_read(grpc_exec_ctx *exec_ctx, grpc_endpoint *secure_ep, static void flush_write_staging_buffer(secure_endpoint *ep, uint8_t **cur, uint8_t **end) { - gpr_slice_buffer_add(&ep->output_buffer, ep->write_staging_buffer); - ep->write_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE); - *cur = GPR_SLICE_START_PTR(ep->write_staging_buffer); - *end = GPR_SLICE_END_PTR(ep->write_staging_buffer); + grpc_slice_buffer_add(&ep->output_buffer, ep->write_staging_buffer); + ep->write_staging_buffer = grpc_slice_malloc(STAGING_BUFFER_SIZE); + *cur = GRPC_SLICE_START_PTR(ep->write_staging_buffer); + *end = GRPC_SLICE_END_PTR(ep->write_staging_buffer); } static void endpoint_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *secure_ep, - gpr_slice_buffer *slices, grpc_closure *cb) { + grpc_slice_buffer *slices, grpc_closure *cb) { GPR_TIMER_BEGIN("secure_endpoint.endpoint_write", 0); unsigned i; tsi_result result = TSI_OK; secure_endpoint *ep = (secure_endpoint *)secure_ep; - uint8_t *cur = GPR_SLICE_START_PTR(ep->write_staging_buffer); - uint8_t *end = GPR_SLICE_END_PTR(ep->write_staging_buffer); + uint8_t *cur = GRPC_SLICE_START_PTR(ep->write_staging_buffer); + uint8_t *end = GRPC_SLICE_END_PTR(ep->write_staging_buffer); - gpr_slice_buffer_reset_and_unref(&ep->output_buffer); + grpc_slice_buffer_reset_and_unref(&ep->output_buffer); if (grpc_trace_secure_endpoint) { for (i = 0; i < slices->count; i++) { char *data = - gpr_dump_slice(slices->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII); + grpc_dump_slice(slices->slices[i], GPR_DUMP_HEX | GPR_DUMP_ASCII); gpr_log(GPR_DEBUG, "WRITE %p: %s", ep, data); gpr_free(data); } } for (i = 0; i < slices->count; i++) { - gpr_slice plain = slices->slices[i]; - uint8_t *message_bytes = GPR_SLICE_START_PTR(plain); - size_t message_size = GPR_SLICE_LENGTH(plain); + grpc_slice plain = slices->slices[i]; + uint8_t *message_bytes = GRPC_SLICE_START_PTR(plain); + size_t message_size = GRPC_SLICE_LENGTH(plain); while (message_size > 0) { size_t protected_buffer_size_to_send = (size_t)(end - cur); size_t processed_message_size = message_size; @@ -310,18 +317,18 @@ static void endpoint_write(grpc_exec_ctx *exec_ctx, grpc_endpoint *secure_ep, flush_write_staging_buffer(ep, &cur, &end); } } while (still_pending_size > 0); - if (cur != GPR_SLICE_START_PTR(ep->write_staging_buffer)) { - gpr_slice_buffer_add( + if (cur != GRPC_SLICE_START_PTR(ep->write_staging_buffer)) { + grpc_slice_buffer_add( &ep->output_buffer, - gpr_slice_split_head( + grpc_slice_split_head( &ep->write_staging_buffer, - (size_t)(cur - GPR_SLICE_START_PTR(ep->write_staging_buffer)))); + (size_t)(cur - GRPC_SLICE_START_PTR(ep->write_staging_buffer)))); } } if (result != TSI_OK) { /* TODO(yangg) do different things according to the error type? */ - gpr_slice_buffer_reset_and_unref(&ep->output_buffer); + grpc_slice_buffer_reset_and_unref(&ep->output_buffer); grpc_exec_ctx_sched( exec_ctx, cb, grpc_set_tsi_error_result(GRPC_ERROR_CREATE("Wrap failed"), result), @@ -365,6 +372,8 @@ static char *endpoint_get_peer(grpc_endpoint *secure_ep) { return grpc_endpoint_get_peer(ep->wrapped_ep); } +static int endpoint_get_fd(grpc_endpoint *secure_ep) { return -1; } + static grpc_workqueue *endpoint_get_workqueue(grpc_endpoint *secure_ep) { secure_endpoint *ep = (secure_endpoint *)secure_ep; return grpc_endpoint_get_workqueue(ep->wrapped_ep); @@ -384,25 +393,26 @@ static const grpc_endpoint_vtable vtable = {endpoint_read, endpoint_shutdown, endpoint_destroy, endpoint_get_resource_user, - endpoint_get_peer}; + endpoint_get_peer, + endpoint_get_fd}; grpc_endpoint *grpc_secure_endpoint_create( struct tsi_frame_protector *protector, grpc_endpoint *transport, - gpr_slice *leftover_slices, size_t leftover_nslices) { + grpc_slice *leftover_slices, size_t leftover_nslices) { size_t i; secure_endpoint *ep = (secure_endpoint *)gpr_malloc(sizeof(secure_endpoint)); ep->base.vtable = &vtable; ep->wrapped_ep = transport; ep->protector = protector; - gpr_slice_buffer_init(&ep->leftover_bytes); + grpc_slice_buffer_init(&ep->leftover_bytes); for (i = 0; i < leftover_nslices; i++) { - gpr_slice_buffer_add(&ep->leftover_bytes, - gpr_slice_ref(leftover_slices[i])); + grpc_slice_buffer_add(&ep->leftover_bytes, + grpc_slice_ref(leftover_slices[i])); } - ep->write_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE); - ep->read_staging_buffer = gpr_slice_malloc(STAGING_BUFFER_SIZE); - gpr_slice_buffer_init(&ep->output_buffer); - gpr_slice_buffer_init(&ep->source_buffer); + ep->write_staging_buffer = grpc_slice_malloc(STAGING_BUFFER_SIZE); + ep->read_staging_buffer = grpc_slice_malloc(STAGING_BUFFER_SIZE); + grpc_slice_buffer_init(&ep->output_buffer); + grpc_slice_buffer_init(&ep->source_buffer); ep->read_buffer = NULL; grpc_closure_init(&ep->on_read, on_read, ep); gpr_mu_init(&ep->protector_mu); diff --git a/src/core/lib/security/transport/secure_endpoint.h b/src/core/lib/security/transport/secure_endpoint.h index d00075b769..a61f40a4fa 100644 --- a/src/core/lib/security/transport/secure_endpoint.h +++ b/src/core/lib/security/transport/secure_endpoint.h @@ -34,7 +34,7 @@ #ifndef GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURE_ENDPOINT_H #define GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURE_ENDPOINT_H -#include <grpc/support/slice.h> +#include <grpc/slice.h> #include "src/core/lib/iomgr/endpoint.h" struct tsi_frame_protector; @@ -44,6 +44,6 @@ extern int grpc_trace_secure_endpoint; /* Takes ownership of protector and to_wrap, and refs leftover_slices. */ grpc_endpoint *grpc_secure_endpoint_create( struct tsi_frame_protector *protector, grpc_endpoint *to_wrap, - gpr_slice *leftover_slices, size_t leftover_nslices); + grpc_slice *leftover_slices, size_t leftover_nslices); #endif /* GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURE_ENDPOINT_H */ diff --git a/src/core/lib/security/transport/security_connector.c b/src/core/lib/security/transport/security_connector.c index ebf72a3abb..a2e0c7c7c7 100644 --- a/src/core/lib/security/transport/security_connector.c +++ b/src/core/lib/security/transport/security_connector.c @@ -36,18 +36,18 @@ #include <stdbool.h> #include <string.h> +#include <grpc/slice_buffer.h> #include <grpc/support/alloc.h> #include <grpc/support/host_port.h> #include <grpc/support/log.h> -#include <grpc/support/slice_buffer.h> #include <grpc/support/string_util.h> #include "src/core/ext/transport/chttp2/alpn/alpn.h" #include "src/core/lib/iomgr/load_file.h" #include "src/core/lib/security/context/security_context.h" #include "src/core/lib/security/credentials/credentials.h" -#include "src/core/lib/security/transport/handshake.h" #include "src/core/lib/security/transport/secure_endpoint.h" +#include "src/core/lib/security/transport/security_handshaker.h" #include "src/core/lib/support/env.h" #include "src/core/lib/support/string.h" #include "src/core/lib/tsi/fake_transport_security.h" @@ -111,58 +111,34 @@ const tsi_peer_property *tsi_peer_get_property_by_name(const tsi_peer *peer, return NULL; } -void grpc_server_security_connector_shutdown( - grpc_exec_ctx *exec_ctx, grpc_server_security_connector *connector) { - grpc_security_connector_handshake_list *tmp; - gpr_mu_lock(&connector->mu); - while (connector->handshaking_handshakes) { - tmp = connector->handshaking_handshakes; - grpc_security_handshake_shutdown( - exec_ctx, connector->handshaking_handshakes->handshake); - connector->handshaking_handshakes = tmp->next; - gpr_free(tmp); +void grpc_channel_security_connector_create_handshakers( + grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *connector, + grpc_handshake_manager *handshake_mgr) { + if (connector != NULL) { + connector->create_handshakers(exec_ctx, connector, handshake_mgr); } - gpr_mu_unlock(&connector->mu); } -void grpc_channel_security_connector_do_handshake( - grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc, - grpc_endpoint *nonsecure_endpoint, gpr_slice_buffer *read_buffer, - gpr_timespec deadline, grpc_security_handshake_done_cb cb, - void *user_data) { - if (sc == NULL || nonsecure_endpoint == NULL) { - gpr_free(read_buffer); - cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL); - } else { - sc->do_handshake(exec_ctx, sc, nonsecure_endpoint, read_buffer, deadline, - cb, user_data); - } -} - -void grpc_server_security_connector_do_handshake( - grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc, - grpc_tcp_server_acceptor *acceptor, grpc_endpoint *nonsecure_endpoint, - gpr_slice_buffer *read_buffer, gpr_timespec deadline, - grpc_security_handshake_done_cb cb, void *user_data) { - if (sc == NULL || nonsecure_endpoint == NULL) { - gpr_free(read_buffer); - cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL, NULL); - } else { - sc->do_handshake(exec_ctx, sc, acceptor, nonsecure_endpoint, read_buffer, - deadline, cb, user_data); +void grpc_server_security_connector_create_handshakers( + grpc_exec_ctx *exec_ctx, grpc_server_security_connector *connector, + grpc_handshake_manager *handshake_mgr) { + if (connector != NULL) { + connector->create_handshakers(exec_ctx, connector, handshake_mgr); } } void grpc_security_connector_check_peer(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc, tsi_peer peer, - grpc_security_peer_check_cb cb, - void *user_data) { + grpc_auth_context **auth_context, + grpc_closure *on_peer_checked) { if (sc == NULL) { - cb(exec_ctx, user_data, GRPC_SECURITY_ERROR, NULL); + grpc_exec_ctx_sched( + exec_ctx, on_peer_checked, + GRPC_ERROR_CREATE("cannot check peer -- no security connector"), NULL); tsi_peer_destruct(&peer); } else { - sc->vtable->check_peer(exec_ctx, sc, peer, cb, user_data); + sc->vtable->check_peer(exec_ctx, sc, peer, auth_context, on_peer_checked); } } @@ -262,45 +238,41 @@ static void fake_channel_destroy(grpc_security_connector *sc) { gpr_free(sc); } -static void fake_server_destroy(grpc_security_connector *sc) { - grpc_server_security_connector *c = (grpc_server_security_connector *)sc; - gpr_mu_destroy(&c->mu); - gpr_free(sc); -} +static void fake_server_destroy(grpc_security_connector *sc) { gpr_free(sc); } static void fake_check_peer(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc, tsi_peer peer, - grpc_security_peer_check_cb cb, void *user_data) { + grpc_auth_context **auth_context, + grpc_closure *on_peer_checked) { const char *prop_name; - grpc_security_status status = GRPC_SECURITY_OK; - grpc_auth_context *auth_context = NULL; + grpc_error *error = GRPC_ERROR_NONE; + *auth_context = NULL; if (peer.property_count != 1) { - gpr_log(GPR_ERROR, "Fake peers should only have 1 property."); - status = GRPC_SECURITY_ERROR; + error = GRPC_ERROR_CREATE("Fake peers should only have 1 property."); goto end; } prop_name = peer.properties[0].name; if (prop_name == NULL || strcmp(prop_name, TSI_CERTIFICATE_TYPE_PEER_PROPERTY)) { - gpr_log(GPR_ERROR, "Unexpected property in fake peer: %s.", - prop_name == NULL ? "<EMPTY>" : prop_name); - status = GRPC_SECURITY_ERROR; + char *msg; + gpr_asprintf(&msg, "Unexpected property in fake peer: %s.", + prop_name == NULL ? "<EMPTY>" : prop_name); + error = GRPC_ERROR_CREATE(msg); + gpr_free(msg); goto end; } if (strncmp(peer.properties[0].value.data, TSI_FAKE_CERTIFICATE_TYPE, peer.properties[0].value.length)) { - gpr_log(GPR_ERROR, "Invalid value for cert type property."); - status = GRPC_SECURITY_ERROR; + error = GRPC_ERROR_CREATE("Invalid value for cert type property."); goto end; } - auth_context = grpc_auth_context_create(NULL); + *auth_context = grpc_auth_context_create(NULL); grpc_auth_context_add_cstring_property( - auth_context, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME, + *auth_context, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME, GRPC_FAKE_TRANSPORT_SECURITY_TYPE); end: - cb(exec_ctx, user_data, status, auth_context); - grpc_auth_context_unref(auth_context); + grpc_exec_ctx_sched(exec_ctx, on_peer_checked, error, NULL); tsi_peer_destruct(&peer); } @@ -313,26 +285,20 @@ static void fake_channel_check_call_host(grpc_exec_ctx *exec_ctx, cb(exec_ctx, user_data, GRPC_SECURITY_OK); } -static void fake_channel_do_handshake(grpc_exec_ctx *exec_ctx, - grpc_channel_security_connector *sc, - grpc_endpoint *nonsecure_endpoint, - gpr_slice_buffer *read_buffer, - gpr_timespec deadline, - grpc_security_handshake_done_cb cb, - void *user_data) { - grpc_do_security_handshake(exec_ctx, tsi_create_fake_handshaker(1), &sc->base, - true, nonsecure_endpoint, read_buffer, deadline, - cb, user_data); +static void fake_channel_create_handshakers( + grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc, + grpc_handshake_manager *handshake_mgr) { + grpc_security_create_handshakers( + exec_ctx, tsi_create_fake_handshaker(true /* is_client */), &sc->base, + handshake_mgr); } -static void fake_server_do_handshake( +static void fake_server_create_handshakers( grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc, - grpc_tcp_server_acceptor *acceptor, grpc_endpoint *nonsecure_endpoint, - gpr_slice_buffer *read_buffer, gpr_timespec deadline, - grpc_security_handshake_done_cb cb, void *user_data) { - grpc_do_security_handshake(exec_ctx, tsi_create_fake_handshaker(0), &sc->base, - false, nonsecure_endpoint, read_buffer, deadline, - cb, user_data); + grpc_handshake_manager *handshake_mgr) { + grpc_security_create_handshakers( + exec_ctx, tsi_create_fake_handshaker(false /* is_client */), &sc->base, + handshake_mgr); } static grpc_security_connector_vtable fake_channel_vtable = { @@ -350,7 +316,7 @@ grpc_channel_security_connector *grpc_fake_channel_security_connector_create( c->base.vtable = &fake_channel_vtable; c->request_metadata_creds = grpc_call_credentials_ref(request_metadata_creds); c->check_call_host = fake_channel_check_call_host; - c->do_handshake = fake_channel_do_handshake; + c->create_handshakers = fake_channel_create_handshakers; return c; } @@ -362,8 +328,7 @@ grpc_server_security_connector *grpc_fake_server_security_connector_create( gpr_ref_init(&c->base.refcount, 1); c->base.vtable = &fake_server_vtable; c->base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME; - c->do_handshake = fake_server_do_handshake; - gpr_mu_init(&c->mu); + c->create_handshakers = fake_server_create_handshakers; return c; } @@ -396,11 +361,9 @@ static void ssl_channel_destroy(grpc_security_connector *sc) { static void ssl_server_destroy(grpc_security_connector *sc) { grpc_ssl_server_security_connector *c = (grpc_ssl_server_security_connector *)sc; - if (c->handshaker_factory != NULL) { tsi_ssl_handshaker_factory_destroy(c->handshaker_factory); } - gpr_mu_destroy(&c->base.mu); gpr_free(sc); } @@ -419,49 +382,33 @@ static grpc_security_status ssl_create_handshaker( return GRPC_SECURITY_OK; } -static void ssl_channel_do_handshake(grpc_exec_ctx *exec_ctx, - grpc_channel_security_connector *sc, - grpc_endpoint *nonsecure_endpoint, - gpr_slice_buffer *read_buffer, - gpr_timespec deadline, - grpc_security_handshake_done_cb cb, - void *user_data) { +static void ssl_channel_create_handshakers( + grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *sc, + grpc_handshake_manager *handshake_mgr) { grpc_ssl_channel_security_connector *c = (grpc_ssl_channel_security_connector *)sc; - tsi_handshaker *handshaker; - grpc_security_status status = ssl_create_handshaker( - c->handshaker_factory, true, - c->overridden_target_name != NULL ? c->overridden_target_name - : c->target_name, - &handshaker); - if (status != GRPC_SECURITY_OK) { - gpr_free(read_buffer); - cb(exec_ctx, user_data, status, NULL, NULL); - } else { - grpc_do_security_handshake(exec_ctx, handshaker, &sc->base, true, - nonsecure_endpoint, read_buffer, deadline, cb, - user_data); - } -} - -static void ssl_server_do_handshake( + // Instantiate TSI handshaker. + tsi_handshaker *tsi_hs = NULL; + ssl_create_handshaker(c->handshaker_factory, true /* is_client */, + c->overridden_target_name != NULL + ? c->overridden_target_name + : c->target_name, + &tsi_hs); + // Create handshakers. + grpc_security_create_handshakers(exec_ctx, tsi_hs, &sc->base, handshake_mgr); +} + +static void ssl_server_create_handshakers( grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc, - grpc_tcp_server_acceptor *acceptor, grpc_endpoint *nonsecure_endpoint, - gpr_slice_buffer *read_buffer, gpr_timespec deadline, - grpc_security_handshake_done_cb cb, void *user_data) { + grpc_handshake_manager *handshake_mgr) { grpc_ssl_server_security_connector *c = (grpc_ssl_server_security_connector *)sc; - tsi_handshaker *handshaker; - grpc_security_status status = - ssl_create_handshaker(c->handshaker_factory, false, NULL, &handshaker); - if (status != GRPC_SECURITY_OK) { - gpr_free(read_buffer); - cb(exec_ctx, user_data, status, NULL, NULL); - } else { - grpc_do_security_handshake(exec_ctx, handshaker, &sc->base, false, - nonsecure_endpoint, read_buffer, deadline, cb, - user_data); - } + // Instantiate TSI handshaker. + tsi_handshaker *tsi_hs = NULL; + ssl_create_handshaker(c->handshaker_factory, false /* is_client */, + NULL /* peer_name */, &tsi_hs); + // Create handshakers. + grpc_security_create_handshakers(exec_ctx, tsi_hs, &sc->base, handshake_mgr); } static int ssl_host_matches_name(const tsi_peer *peer, const char *peer_name) { @@ -518,57 +465,53 @@ grpc_auth_context *tsi_ssl_peer_to_auth_context(const tsi_peer *peer) { return ctx; } -static grpc_security_status ssl_check_peer(grpc_security_connector *sc, - const char *peer_name, - const tsi_peer *peer, - grpc_auth_context **auth_context) { +static grpc_error *ssl_check_peer(grpc_security_connector *sc, + const char *peer_name, const tsi_peer *peer, + grpc_auth_context **auth_context) { /* Check the ALPN. */ const tsi_peer_property *p = tsi_peer_get_property_by_name(peer, TSI_SSL_ALPN_SELECTED_PROTOCOL); if (p == NULL) { - gpr_log(GPR_ERROR, "Missing selected ALPN property."); - return GRPC_SECURITY_ERROR; + return GRPC_ERROR_CREATE( + "Cannot check peer: missing selected ALPN property."); } if (!grpc_chttp2_is_alpn_version_supported(p->value.data, p->value.length)) { - gpr_log(GPR_ERROR, "Invalid ALPN value."); - return GRPC_SECURITY_ERROR; + return GRPC_ERROR_CREATE("Cannot check peer: invalid ALPN value."); } /* Check the peer name if specified. */ if (peer_name != NULL && !ssl_host_matches_name(peer, peer_name)) { - gpr_log(GPR_ERROR, "Peer name %s is not in peer certificate", peer_name); - return GRPC_SECURITY_ERROR; + char *msg; + gpr_asprintf(&msg, "Peer name %s is not in peer certificate", peer_name); + grpc_error *error = GRPC_ERROR_CREATE(msg); + gpr_free(msg); + return error; } *auth_context = tsi_ssl_peer_to_auth_context(peer); - return GRPC_SECURITY_OK; + return GRPC_ERROR_NONE; } static void ssl_channel_check_peer(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc, tsi_peer peer, - grpc_security_peer_check_cb cb, - void *user_data) { + grpc_auth_context **auth_context, + grpc_closure *on_peer_checked) { grpc_ssl_channel_security_connector *c = (grpc_ssl_channel_security_connector *)sc; - grpc_security_status status; - grpc_auth_context *auth_context = NULL; - status = ssl_check_peer(sc, c->overridden_target_name != NULL - ? c->overridden_target_name - : c->target_name, - &peer, &auth_context); - cb(exec_ctx, user_data, status, auth_context); - grpc_auth_context_unref(auth_context); + grpc_error *error = ssl_check_peer(sc, c->overridden_target_name != NULL + ? c->overridden_target_name + : c->target_name, + &peer, auth_context); + grpc_exec_ctx_sched(exec_ctx, on_peer_checked, error, NULL); tsi_peer_destruct(&peer); } static void ssl_server_check_peer(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc, tsi_peer peer, - grpc_security_peer_check_cb cb, - void *user_data) { - grpc_auth_context *auth_context = NULL; - grpc_security_status status = ssl_check_peer(sc, NULL, &peer, &auth_context); + grpc_auth_context **auth_context, + grpc_closure *on_peer_checked) { + grpc_error *error = ssl_check_peer(sc, NULL, &peer, auth_context); tsi_peer_destruct(&peer); - cb(exec_ctx, user_data, status, auth_context); - grpc_auth_context_unref(auth_context); + grpc_exec_ctx_sched(exec_ctx, on_peer_checked, error, NULL); } static void add_shallow_auth_property_to_peer(tsi_peer *peer, @@ -642,8 +585,8 @@ static grpc_security_connector_vtable ssl_channel_vtable = { static grpc_security_connector_vtable ssl_server_vtable = { ssl_server_destroy, ssl_server_check_peer}; -static gpr_slice compute_default_pem_root_certs_once(void) { - gpr_slice result = gpr_empty_slice(); +static grpc_slice compute_default_pem_root_certs_once(void) { + grpc_slice result = gpr_empty_slice(); /* First try to load the roots from the environment. */ char *default_root_certs_path = @@ -656,17 +599,17 @@ static gpr_slice compute_default_pem_root_certs_once(void) { /* Try overridden roots if needed. */ grpc_ssl_roots_override_result ovrd_res = GRPC_SSL_ROOTS_OVERRIDE_FAIL; - if (GPR_SLICE_IS_EMPTY(result) && ssl_roots_override_cb != NULL) { + if (GRPC_SLICE_IS_EMPTY(result) && ssl_roots_override_cb != NULL) { char *pem_root_certs = NULL; ovrd_res = ssl_roots_override_cb(&pem_root_certs); if (ovrd_res == GRPC_SSL_ROOTS_OVERRIDE_OK) { GPR_ASSERT(pem_root_certs != NULL); - result = gpr_slice_new(pem_root_certs, strlen(pem_root_certs), gpr_free); + result = grpc_slice_new(pem_root_certs, strlen(pem_root_certs), gpr_free); } } /* Fall back to installed certs if needed. */ - if (GPR_SLICE_IS_EMPTY(result) && + if (GRPC_SLICE_IS_EMPTY(result) && ovrd_res != GRPC_SSL_ROOTS_OVERRIDE_FAIL_PERMANENTLY) { GRPC_LOG_IF_ERROR("load_file", grpc_load_file(installed_roots_path, 0, &result)); @@ -674,13 +617,13 @@ static gpr_slice compute_default_pem_root_certs_once(void) { return result; } -static gpr_slice default_pem_root_certs; +static grpc_slice default_pem_root_certs; static void init_default_pem_root_certs(void) { default_pem_root_certs = compute_default_pem_root_certs_once(); } -gpr_slice grpc_get_default_ssl_roots_for_testing(void) { +grpc_slice grpc_get_default_ssl_roots_for_testing(void) { return compute_default_pem_root_certs_once(); } @@ -714,8 +657,8 @@ size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs) { loading all the roots once for the lifetime of the process. */ static gpr_once once = GPR_ONCE_INIT; gpr_once_init(&once, init_default_pem_root_certs); - *pem_root_certs = GPR_SLICE_START_PTR(default_pem_root_certs); - return GPR_SLICE_LENGTH(default_pem_root_certs); + *pem_root_certs = GRPC_SLICE_START_PTR(default_pem_root_certs); + return GRPC_SLICE_LENGTH(default_pem_root_certs); } grpc_security_status grpc_ssl_channel_security_connector_create( @@ -765,7 +708,7 @@ grpc_security_status grpc_ssl_channel_security_connector_create( c->base.request_metadata_creds = grpc_call_credentials_ref(request_metadata_creds); c->base.check_call_host = ssl_channel_check_call_host; - c->base.do_handshake = ssl_channel_do_handshake; + c->base.create_handshakers = ssl_channel_create_handshakers; gpr_split_host_port(target_name, &c->target_name, &port); gpr_free(port); if (overridden_target_name != NULL) { @@ -840,8 +783,7 @@ grpc_security_status grpc_ssl_server_security_connector_create( *sc = NULL; goto error; } - gpr_mu_init(&c->base.mu); - c->base.do_handshake = ssl_server_do_handshake; + c->base.create_handshakers = ssl_server_create_handshakers; *sc = &c->base; gpr_free((void *)alpn_protocol_strings); gpr_free(alpn_protocol_string_lengths); diff --git a/src/core/lib/security/transport/security_connector.h b/src/core/lib/security/transport/security_connector.h index 0b5b44bf1a..696db0e02e 100644 --- a/src/core/lib/security/transport/security_connector.h +++ b/src/core/lib/security/transport/security_connector.h @@ -35,6 +35,8 @@ #define GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURITY_CONNECTOR_H #include <grpc/grpc_security.h> + +#include "src/core/lib/channel/handshaker.h" #include "src/core/lib/iomgr/endpoint.h" #include "src/core/lib/iomgr/tcp_server.h" #include "src/core/lib/tsi/transport_security_interface.h" @@ -57,21 +59,11 @@ typedef struct grpc_security_connector grpc_security_connector; #define GRPC_SECURITY_CONNECTOR_ARG "grpc.security_connector" -typedef void (*grpc_security_peer_check_cb)(grpc_exec_ctx *exec_ctx, - void *user_data, - grpc_security_status status, - grpc_auth_context *auth_context); - -/* Ownership of the secure_endpoint is transfered. */ -typedef void (*grpc_security_handshake_done_cb)( - grpc_exec_ctx *exec_ctx, void *user_data, grpc_security_status status, - grpc_endpoint *secure_endpoint, grpc_auth_context *auth_context); - typedef struct { void (*destroy)(grpc_security_connector *sc); void (*check_peer)(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc, - tsi_peer peer, grpc_security_peer_check_cb cb, - void *user_data); + tsi_peer peer, grpc_auth_context **auth_context, + grpc_closure *on_peer_checked); } grpc_security_connector_vtable; typedef struct grpc_security_connector_handshake_list { @@ -106,12 +98,12 @@ void grpc_security_connector_unref(grpc_security_connector *policy); #endif /* Check the peer. Callee takes ownership of the peer object. - The callback will include the resulting auth_context. */ + Sets *auth_context and invokes on_peer_checked when done. */ void grpc_security_connector_check_peer(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc, tsi_peer peer, - grpc_security_peer_check_cb cb, - void *user_data); + grpc_auth_context **auth_context, + grpc_closure *on_peer_checked); /* Util to encapsulate the connector in a channel arg. */ grpc_arg grpc_security_connector_to_arg(grpc_security_connector *sc); @@ -141,11 +133,9 @@ struct grpc_channel_security_connector { grpc_channel_security_connector *sc, const char *host, grpc_auth_context *auth_context, grpc_security_call_host_check_cb cb, void *user_data); - void (*do_handshake)(grpc_exec_ctx *exec_ctx, - grpc_channel_security_connector *sc, - grpc_endpoint *nonsecure_endpoint, - gpr_slice_buffer *read_buffer, gpr_timespec deadline, - grpc_security_handshake_done_cb cb, void *user_data); + void (*create_handshakers)(grpc_exec_ctx *exec_ctx, + grpc_channel_security_connector *sc, + grpc_handshake_manager *handshake_mgr); }; /* Checks that the host that will be set for a call is acceptable. */ @@ -154,11 +144,10 @@ void grpc_channel_security_connector_check_call_host( const char *host, grpc_auth_context *auth_context, grpc_security_call_host_check_cb cb, void *user_data); -/* Handshake. */ -void grpc_channel_security_connector_do_handshake( +/* Registers handshakers with \a handshake_mgr. */ +void grpc_channel_security_connector_create_handshakers( grpc_exec_ctx *exec_ctx, grpc_channel_security_connector *connector, - grpc_endpoint *nonsecure_endpoint, gpr_slice_buffer *read_buffer, - gpr_timespec deadline, grpc_security_handshake_done_cb cb, void *user_data); + grpc_handshake_manager *handshake_mgr); /* --- server_security_connector object. --- @@ -169,25 +158,14 @@ typedef struct grpc_server_security_connector grpc_server_security_connector; struct grpc_server_security_connector { grpc_security_connector base; - gpr_mu mu; - grpc_security_connector_handshake_list *handshaking_handshakes; - const grpc_channel_args *channel_args; - void (*do_handshake)(grpc_exec_ctx *exec_ctx, - grpc_server_security_connector *sc, - grpc_tcp_server_acceptor *acceptor, - grpc_endpoint *nonsecure_endpoint, - gpr_slice_buffer *read_buffer, gpr_timespec deadline, - grpc_security_handshake_done_cb cb, void *user_data); + void (*create_handshakers)(grpc_exec_ctx *exec_ctx, + grpc_server_security_connector *sc, + grpc_handshake_manager *handshake_mgr); }; -void grpc_server_security_connector_do_handshake( +void grpc_server_security_connector_create_handshakers( grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc, - grpc_tcp_server_acceptor *acceptor, grpc_endpoint *nonsecure_endpoint, - gpr_slice_buffer *read_buffer, gpr_timespec deadline, - grpc_security_handshake_done_cb cb, void *user_data); - -void grpc_server_security_connector_shutdown( - grpc_exec_ctx *exec_ctx, grpc_server_security_connector *connector); + grpc_handshake_manager *handshake_mgr); /* --- Creation security connectors. --- */ @@ -233,7 +211,7 @@ grpc_security_status grpc_ssl_channel_security_connector_create( size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs); /* Exposed for TESTING ONLY!. */ -gpr_slice grpc_get_default_ssl_roots_for_testing(void); +grpc_slice grpc_get_default_ssl_roots_for_testing(void); /* Config for ssl servers. */ typedef struct { diff --git a/src/core/lib/security/transport/security_handshaker.c b/src/core/lib/security/transport/security_handshaker.c new file mode 100644 index 0000000000..fc01bec2f2 --- /dev/null +++ b/src/core/lib/security/transport/security_handshaker.c @@ -0,0 +1,450 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "src/core/lib/security/transport/security_handshaker.h" + +#include <stdbool.h> +#include <string.h> + +#include <grpc/slice_buffer.h> +#include <grpc/support/alloc.h> +#include <grpc/support/log.h> + +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/channel/handshaker.h" +#include "src/core/lib/security/context/security_context.h" +#include "src/core/lib/security/transport/secure_endpoint.h" +#include "src/core/lib/security/transport/tsi_error.h" + +#define GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE 256 + +typedef struct { + grpc_handshaker base; + + // State set at creation time. + tsi_handshaker *handshaker; + grpc_security_connector *connector; + + gpr_mu mu; + gpr_refcount refs; + + bool shutdown; + // Endpoint and read buffer to destroy after a shutdown. + grpc_endpoint *endpoint_to_destroy; + grpc_slice_buffer *read_buffer_to_destroy; + + // State saved while performing the handshake. + grpc_handshaker_args *args; + grpc_closure *on_handshake_done; + + unsigned char *handshake_buffer; + size_t handshake_buffer_size; + grpc_slice_buffer left_overs; + grpc_slice_buffer outgoing; + grpc_closure on_handshake_data_sent_to_peer; + grpc_closure on_handshake_data_received_from_peer; + grpc_closure on_peer_checked; + grpc_auth_context *auth_context; +} security_handshaker; + +static void security_handshaker_unref(grpc_exec_ctx *exec_ctx, + security_handshaker *h) { + if (gpr_unref(&h->refs)) { + gpr_mu_destroy(&h->mu); + tsi_handshaker_destroy(h->handshaker); + if (h->endpoint_to_destroy != NULL) { + grpc_endpoint_destroy(exec_ctx, h->endpoint_to_destroy); + } + if (h->read_buffer_to_destroy != NULL) { + grpc_slice_buffer_destroy(h->read_buffer_to_destroy); + gpr_free(h->read_buffer_to_destroy); + } + gpr_free(h->handshake_buffer); + grpc_slice_buffer_destroy(&h->left_overs); + grpc_slice_buffer_destroy(&h->outgoing); + GRPC_AUTH_CONTEXT_UNREF(h->auth_context, "handshake"); + GRPC_SECURITY_CONNECTOR_UNREF(h->connector, "handshake"); + gpr_free(h); + } +} + +// Set args fields to NULL, saving the endpoint and read buffer for +// later destruction. +static void cleanup_args_for_failure_locked(security_handshaker *h) { + h->endpoint_to_destroy = h->args->endpoint; + h->args->endpoint = NULL; + h->read_buffer_to_destroy = h->args->read_buffer; + h->args->read_buffer = NULL; + grpc_channel_args_destroy(h->args->args); + h->args->args = NULL; +} + +// If the handshake failed or we're shutting down, clean up and invoke the +// callback with the error. +static void security_handshake_failed_locked(grpc_exec_ctx *exec_ctx, + security_handshaker *h, + grpc_error *error) { + if (error == GRPC_ERROR_NONE) { + // If we were shut down after the handshake succeeded but before an + // endpoint callback was invoked, we need to generate our own error. + error = GRPC_ERROR_CREATE("Handshaker shutdown"); + } + const char *msg = grpc_error_string(error); + gpr_log(GPR_DEBUG, "Security handshake failed: %s", msg); + grpc_error_free_string(msg); + if (!h->shutdown) { + // TODO(ctiller): It is currently necessary to shutdown endpoints + // before destroying them, even if we know that there are no + // pending read/write callbacks. This should be fixed, at which + // point this can be removed. + grpc_endpoint_shutdown(exec_ctx, h->args->endpoint); + // Not shutting down, so the write failed. Clean up before + // invoking the callback. + cleanup_args_for_failure_locked(h); + } + // Invoke callback. + grpc_exec_ctx_sched(exec_ctx, h->on_handshake_done, error, NULL); +} + +static void on_peer_checked(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + security_handshaker *h = arg; + gpr_mu_lock(&h->mu); + if (error != GRPC_ERROR_NONE || h->shutdown) { + security_handshake_failed_locked(exec_ctx, h, GRPC_ERROR_REF(error)); + goto done; + } + // Get frame protector. + tsi_frame_protector *protector; + tsi_result result = + tsi_handshaker_create_frame_protector(h->handshaker, NULL, &protector); + if (result != TSI_OK) { + error = grpc_set_tsi_error_result( + GRPC_ERROR_CREATE("Frame protector creation failed"), result); + security_handshake_failed_locked(exec_ctx, h, error); + goto done; + } + // Success. + // Create secure endpoint. + h->args->endpoint = grpc_secure_endpoint_create( + protector, h->args->endpoint, h->left_overs.slices, h->left_overs.count); + h->left_overs.count = 0; + h->left_overs.length = 0; + // Clear out the read buffer before it gets passed to the transport, + // since any excess bytes were already copied to h->left_overs. + grpc_slice_buffer_reset_and_unref(h->args->read_buffer); + // Add auth context to channel args. + grpc_arg auth_context_arg = grpc_auth_context_to_arg(h->auth_context); + grpc_channel_args *tmp_args = h->args->args; + h->args->args = + grpc_channel_args_copy_and_add(tmp_args, &auth_context_arg, 1); + grpc_channel_args_destroy(tmp_args); + // Invoke callback. + grpc_exec_ctx_sched(exec_ctx, h->on_handshake_done, GRPC_ERROR_NONE, NULL); + // Set shutdown to true so that subsequent calls to + // security_handshaker_shutdown() do nothing. + h->shutdown = true; +done: + gpr_mu_unlock(&h->mu); + security_handshaker_unref(exec_ctx, h); +} + +static grpc_error *check_peer_locked(grpc_exec_ctx *exec_ctx, + security_handshaker *h) { + tsi_peer peer; + tsi_result result = tsi_handshaker_extract_peer(h->handshaker, &peer); + if (result != TSI_OK) { + return grpc_set_tsi_error_result( + GRPC_ERROR_CREATE("Peer extraction failed"), result); + } + grpc_security_connector_check_peer(exec_ctx, h->connector, peer, + &h->auth_context, &h->on_peer_checked); + return GRPC_ERROR_NONE; +} + +static grpc_error *send_handshake_bytes_to_peer_locked(grpc_exec_ctx *exec_ctx, + security_handshaker *h) { + // Get data to send. + tsi_result result = TSI_OK; + size_t offset = 0; + do { + size_t to_send_size = h->handshake_buffer_size - offset; + result = tsi_handshaker_get_bytes_to_send_to_peer( + h->handshaker, h->handshake_buffer + offset, &to_send_size); + offset += to_send_size; + if (result == TSI_INCOMPLETE_DATA) { + h->handshake_buffer_size *= 2; + h->handshake_buffer = + gpr_realloc(h->handshake_buffer, h->handshake_buffer_size); + } + } while (result == TSI_INCOMPLETE_DATA); + if (result != TSI_OK) { + return grpc_set_tsi_error_result(GRPC_ERROR_CREATE("Handshake failed"), + result); + } + // Send data. + grpc_slice to_send = + grpc_slice_from_copied_buffer((const char *)h->handshake_buffer, offset); + grpc_slice_buffer_reset_and_unref(&h->outgoing); + grpc_slice_buffer_add(&h->outgoing, to_send); + grpc_endpoint_write(exec_ctx, h->args->endpoint, &h->outgoing, + &h->on_handshake_data_sent_to_peer); + return GRPC_ERROR_NONE; +} + +static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx, + void *arg, grpc_error *error) { + security_handshaker *h = arg; + gpr_mu_lock(&h->mu); + if (error != GRPC_ERROR_NONE || h->shutdown) { + security_handshake_failed_locked( + exec_ctx, h, + GRPC_ERROR_CREATE_REFERENCING("Handshake read failed", &error, 1)); + gpr_mu_unlock(&h->mu); + security_handshaker_unref(exec_ctx, h); + return; + } + // Process received data. + tsi_result result = TSI_OK; + size_t consumed_slice_size = 0; + size_t i; + for (i = 0; i < h->args->read_buffer->count; i++) { + consumed_slice_size = GRPC_SLICE_LENGTH(h->args->read_buffer->slices[i]); + result = tsi_handshaker_process_bytes_from_peer( + h->handshaker, GRPC_SLICE_START_PTR(h->args->read_buffer->slices[i]), + &consumed_slice_size); + if (!tsi_handshaker_is_in_progress(h->handshaker)) break; + } + if (tsi_handshaker_is_in_progress(h->handshaker)) { + /* We may need more data. */ + if (result == TSI_INCOMPLETE_DATA) { + grpc_endpoint_read(exec_ctx, h->args->endpoint, h->args->read_buffer, + &h->on_handshake_data_received_from_peer); + goto done; + } else { + error = send_handshake_bytes_to_peer_locked(exec_ctx, h); + if (error != GRPC_ERROR_NONE) { + security_handshake_failed_locked(exec_ctx, h, error); + gpr_mu_unlock(&h->mu); + security_handshaker_unref(exec_ctx, h); + return; + } + goto done; + } + } + if (result != TSI_OK) { + security_handshake_failed_locked( + exec_ctx, h, grpc_set_tsi_error_result( + GRPC_ERROR_CREATE("Handshake failed"), result)); + gpr_mu_unlock(&h->mu); + security_handshaker_unref(exec_ctx, h); + return; + } + /* Handshake is done and successful this point. */ + bool has_left_overs_in_current_slice = + (consumed_slice_size < + GRPC_SLICE_LENGTH(h->args->read_buffer->slices[i])); + size_t num_left_overs = (has_left_overs_in_current_slice ? 1 : 0) + + h->args->read_buffer->count - i - 1; + if (num_left_overs > 0) { + /* Put the leftovers in our buffer (ownership transfered). */ + if (has_left_overs_in_current_slice) { + grpc_slice_buffer_add( + &h->left_overs, + grpc_slice_split_tail(&h->args->read_buffer->slices[i], + consumed_slice_size)); + /* split_tail above increments refcount. */ + grpc_slice_unref(h->args->read_buffer->slices[i]); + } + grpc_slice_buffer_addn( + &h->left_overs, &h->args->read_buffer->slices[i + 1], + num_left_overs - (size_t)has_left_overs_in_current_slice); + } + // Check peer. + error = check_peer_locked(exec_ctx, h); + if (error != GRPC_ERROR_NONE) { + security_handshake_failed_locked(exec_ctx, h, error); + gpr_mu_unlock(&h->mu); + security_handshaker_unref(exec_ctx, h); + return; + } +done: + gpr_mu_unlock(&h->mu); +} + +static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error) { + security_handshaker *h = arg; + gpr_mu_lock(&h->mu); + if (error != GRPC_ERROR_NONE || h->shutdown) { + security_handshake_failed_locked( + exec_ctx, h, + GRPC_ERROR_CREATE_REFERENCING("Handshake write failed", &error, 1)); + gpr_mu_unlock(&h->mu); + security_handshaker_unref(exec_ctx, h); + return; + } + /* We may be done. */ + if (tsi_handshaker_is_in_progress(h->handshaker)) { + grpc_endpoint_read(exec_ctx, h->args->endpoint, h->args->read_buffer, + &h->on_handshake_data_received_from_peer); + } else { + error = check_peer_locked(exec_ctx, h); + if (error != GRPC_ERROR_NONE) { + security_handshake_failed_locked(exec_ctx, h, error); + gpr_mu_unlock(&h->mu); + security_handshaker_unref(exec_ctx, h); + return; + } + } + gpr_mu_unlock(&h->mu); +} + +// +// public handshaker API +// + +static void security_handshaker_destroy(grpc_exec_ctx *exec_ctx, + grpc_handshaker *handshaker) { + security_handshaker *h = (security_handshaker *)handshaker; + security_handshaker_unref(exec_ctx, h); +} + +static void security_handshaker_shutdown(grpc_exec_ctx *exec_ctx, + grpc_handshaker *handshaker) { + security_handshaker *h = (security_handshaker *)handshaker; + gpr_mu_lock(&h->mu); + if (!h->shutdown) { + h->shutdown = true; + grpc_endpoint_shutdown(exec_ctx, h->args->endpoint); + cleanup_args_for_failure_locked(h); + } + gpr_mu_unlock(&h->mu); +} + +static void security_handshaker_do_handshake(grpc_exec_ctx *exec_ctx, + grpc_handshaker *handshaker, + grpc_tcp_server_acceptor *acceptor, + grpc_closure *on_handshake_done, + grpc_handshaker_args *args) { + security_handshaker *h = (security_handshaker *)handshaker; + gpr_mu_lock(&h->mu); + h->args = args; + h->on_handshake_done = on_handshake_done; + gpr_ref(&h->refs); + grpc_error *error = send_handshake_bytes_to_peer_locked(exec_ctx, h); + if (error != GRPC_ERROR_NONE) { + security_handshake_failed_locked(exec_ctx, h, error); + gpr_mu_unlock(&h->mu); + security_handshaker_unref(exec_ctx, h); + return; + } + gpr_mu_unlock(&h->mu); +} + +static const grpc_handshaker_vtable security_handshaker_vtable = { + security_handshaker_destroy, security_handshaker_shutdown, + security_handshaker_do_handshake}; + +static grpc_handshaker *security_handshaker_create( + grpc_exec_ctx *exec_ctx, tsi_handshaker *handshaker, + grpc_security_connector *connector) { + security_handshaker *h = gpr_malloc(sizeof(security_handshaker)); + memset(h, 0, sizeof(security_handshaker)); + grpc_handshaker_init(&security_handshaker_vtable, &h->base); + h->handshaker = handshaker; + h->connector = GRPC_SECURITY_CONNECTOR_REF(connector, "handshake"); + gpr_mu_init(&h->mu); + gpr_ref_init(&h->refs, 1); + h->handshake_buffer_size = GRPC_INITIAL_HANDSHAKE_BUFFER_SIZE; + h->handshake_buffer = gpr_malloc(h->handshake_buffer_size); + grpc_closure_init(&h->on_handshake_data_sent_to_peer, + on_handshake_data_sent_to_peer, h); + grpc_closure_init(&h->on_handshake_data_received_from_peer, + on_handshake_data_received_from_peer, h); + grpc_closure_init(&h->on_peer_checked, on_peer_checked, h); + grpc_slice_buffer_init(&h->left_overs); + grpc_slice_buffer_init(&h->outgoing); + return &h->base; +} + +// +// fail_handshaker +// + +static void fail_handshaker_destroy(grpc_exec_ctx *exec_ctx, + grpc_handshaker *handshaker) { + gpr_free(handshaker); +} + +static void fail_handshaker_shutdown(grpc_exec_ctx *exec_ctx, + grpc_handshaker *handshaker) {} + +static void fail_handshaker_do_handshake(grpc_exec_ctx *exec_ctx, + grpc_handshaker *handshaker, + grpc_tcp_server_acceptor *acceptor, + grpc_closure *on_handshake_done, + grpc_handshaker_args *args) { + grpc_exec_ctx_sched(exec_ctx, on_handshake_done, + GRPC_ERROR_CREATE("Failed to create security handshaker"), + NULL); +} + +static const grpc_handshaker_vtable fail_handshaker_vtable = { + fail_handshaker_destroy, fail_handshaker_shutdown, + fail_handshaker_do_handshake}; + +static grpc_handshaker *fail_handshaker_create() { + grpc_handshaker *h = gpr_malloc(sizeof(*h)); + grpc_handshaker_init(&fail_handshaker_vtable, h); + return h; +} + +// +// exported functions +// + +void grpc_security_create_handshakers(grpc_exec_ctx *exec_ctx, + tsi_handshaker *handshaker, + grpc_security_connector *connector, + grpc_handshake_manager *handshake_mgr) { + // If no TSI handshaker was created, add a handshaker that always fails. + // Otherwise, add a real security handshaker. + if (handshaker == NULL) { + grpc_handshake_manager_add(handshake_mgr, fail_handshaker_create()); + } else { + grpc_handshake_manager_add( + handshake_mgr, + security_handshaker_create(exec_ctx, handshaker, connector)); + } +} diff --git a/src/core/lib/security/transport/handshake.h b/src/core/lib/security/transport/security_handshaker.h index 53092f5421..f71f43a359 100644 --- a/src/core/lib/security/transport/handshake.h +++ b/src/core/lib/security/transport/security_handshaker.h @@ -31,20 +31,17 @@ * */ -#ifndef GRPC_CORE_LIB_SECURITY_TRANSPORT_HANDSHAKE_H -#define GRPC_CORE_LIB_SECURITY_TRANSPORT_HANDSHAKE_H +#ifndef GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURITY_HANDSHAKER_H +#define GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURITY_HANDSHAKER_H #include "src/core/lib/iomgr/endpoint.h" #include "src/core/lib/security/transport/security_connector.h" -/* Calls the callback upon completion. Takes owership of handshaker and - * read_buffer. */ -void grpc_do_security_handshake( - grpc_exec_ctx *exec_ctx, tsi_handshaker *handshaker, - grpc_security_connector *connector, bool is_client_side, - grpc_endpoint *nonsecure_endpoint, gpr_slice_buffer *read_buffer, - gpr_timespec deadline, grpc_security_handshake_done_cb cb, void *user_data); +/// Creates any necessary security handshakers and adds them to +/// \a handshake_mgr. +void grpc_security_create_handshakers(grpc_exec_ctx *exec_ctx, + tsi_handshaker *handshaker, + grpc_security_connector *connector, + grpc_handshake_manager *handshake_mgr); -void grpc_security_handshake_shutdown(grpc_exec_ctx *exec_ctx, void *handshake); - -#endif /* GRPC_CORE_LIB_SECURITY_TRANSPORT_HANDSHAKE_H */ +#endif /* GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURITY_HANDSHAKER_H */ diff --git a/src/core/lib/security/transport/server_auth_filter.c b/src/core/lib/security/transport/server_auth_filter.c index b2c6815af8..eaa1d0720b 100644 --- a/src/core/lib/security/transport/server_auth_filter.c +++ b/src/core/lib/security/transport/server_auth_filter.c @@ -78,7 +78,7 @@ static grpc_metadata_array metadata_batch_to_md_array( usr_md = &result.metadata[result.count++]; usr_md->key = grpc_mdstr_as_c_string(key); usr_md->value = grpc_mdstr_as_c_string(value); - usr_md->value_length = GPR_SLICE_LENGTH(value->slice); + usr_md->value_length = GRPC_SLICE_LENGTH(value->slice); } return result; } @@ -92,14 +92,14 @@ static grpc_mdelem *remove_consumed_md(void *user_data, grpc_mdelem *md) { /* Maybe we could do a pointer comparison but we do not have any guarantee that the metadata processor used the same pointers for consumed_md in the callback. */ - if (GPR_SLICE_LENGTH(md->key->slice) != strlen(consumed_md->key) || - GPR_SLICE_LENGTH(md->value->slice) != consumed_md->value_length) { + if (GRPC_SLICE_LENGTH(md->key->slice) != strlen(consumed_md->key) || + GRPC_SLICE_LENGTH(md->value->slice) != consumed_md->value_length) { continue; } - if (memcmp(GPR_SLICE_START_PTR(md->key->slice), consumed_md->key, - GPR_SLICE_LENGTH(md->key->slice)) == 0 && - memcmp(GPR_SLICE_START_PTR(md->value->slice), consumed_md->value, - GPR_SLICE_LENGTH(md->value->slice)) == 0) { + if (memcmp(GRPC_SLICE_START_PTR(md->key->slice), consumed_md->key, + GRPC_SLICE_LENGTH(md->key->slice)) == 0 && + memcmp(GRPC_SLICE_START_PTR(md->value->slice), consumed_md->value, + GRPC_SLICE_LENGTH(md->value->slice)) == 0) { return NULL; /* Delete. */ } } @@ -134,14 +134,14 @@ static void on_md_processing_done( grpc_metadata_array_destroy(&calld->md); grpc_exec_ctx_sched(&exec_ctx, calld->on_done_recv, GRPC_ERROR_NONE, NULL); } else { - gpr_slice message; + grpc_slice message; grpc_transport_stream_op *close_op = gpr_malloc(sizeof(*close_op)); memset(close_op, 0, sizeof(*close_op)); grpc_metadata_array_destroy(&calld->md); error_details = error_details != NULL ? error_details : "Authentication metadata processing failed."; - message = gpr_slice_from_copied_string(error_details); + message = grpc_slice_from_copied_string(error_details); calld->transport_op->send_initial_metadata = NULL; if (calld->transport_op->send_message != NULL) { grpc_byte_stream_destroy(&exec_ctx, calld->transport_op->send_message); @@ -278,4 +278,5 @@ const grpc_channel_filter grpc_server_auth_filter = { init_channel_elem, destroy_channel_elem, grpc_call_next_get_peer, + grpc_channel_next_get_info, "server-auth"}; diff --git a/src/core/lib/security/util/b64.c b/src/core/lib/security/util/b64.c index 9da42e4e73..4892e8e621 100644 --- a/src/core/lib/security/util/b64.c +++ b/src/core/lib/security/util/b64.c @@ -120,7 +120,7 @@ char *grpc_base64_encode(const void *vdata, size_t data_size, int url_safe, return result; } -gpr_slice grpc_base64_decode(const char *b64, int url_safe) { +grpc_slice grpc_base64_decode(const char *b64, int url_safe) { return grpc_base64_decode_with_len(b64, strlen(b64), url_safe); } @@ -182,10 +182,10 @@ static int decode_group(const unsigned char *codes, size_t num_codes, return 1; } -gpr_slice grpc_base64_decode_with_len(const char *b64, size_t b64_len, - int url_safe) { - gpr_slice result = gpr_slice_malloc(b64_len); - unsigned char *current = GPR_SLICE_START_PTR(result); +grpc_slice grpc_base64_decode_with_len(const char *b64, size_t b64_len, + int url_safe) { + grpc_slice result = grpc_slice_malloc(b64_len); + unsigned char *current = GRPC_SLICE_START_PTR(result); size_t result_size = 0; unsigned char codes[4]; size_t num_codes = 0; @@ -224,10 +224,10 @@ gpr_slice grpc_base64_decode_with_len(const char *b64, size_t b64_len, !decode_group(codes, num_codes, current, &result_size)) { goto fail; } - GPR_SLICE_SET_LENGTH(result, result_size); + GRPC_SLICE_SET_LENGTH(result, result_size); return result; fail: - gpr_slice_unref(result); + grpc_slice_unref(result); return gpr_empty_slice(); } diff --git a/src/core/lib/security/util/b64.h b/src/core/lib/security/util/b64.h index 6908095287..6ea0b5365b 100644 --- a/src/core/lib/security/util/b64.h +++ b/src/core/lib/security/util/b64.h @@ -34,7 +34,7 @@ #ifndef GRPC_CORE_LIB_SECURITY_UTIL_B64_H #define GRPC_CORE_LIB_SECURITY_UTIL_B64_H -#include <grpc/support/slice.h> +#include <grpc/slice.h> /* Encodes data using base64. It is the caller's responsability to free the returned char * using gpr_free. Returns NULL on NULL input. */ @@ -43,10 +43,10 @@ char *grpc_base64_encode(const void *data, size_t data_size, int url_safe, /* Decodes data according to the base64 specification. Returns an empty slice in case of failure. */ -gpr_slice grpc_base64_decode(const char *b64, int url_safe); +grpc_slice grpc_base64_decode(const char *b64, int url_safe); /* Same as above except that the length is provided by the caller. */ -gpr_slice grpc_base64_decode_with_len(const char *b64, size_t b64_len, - int url_safe); +grpc_slice grpc_base64_decode_with_len(const char *b64, size_t b64_len, + int url_safe); #endif /* GRPC_CORE_LIB_SECURITY_UTIL_B64_H */ |