aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/lib/security/transport/handshake.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/lib/security/transport/handshake.c')
-rw-r--r--src/core/lib/security/transport/handshake.c116
1 files changed, 74 insertions, 42 deletions
diff --git a/src/core/lib/security/transport/handshake.c b/src/core/lib/security/transport/handshake.c
index 6561f4b47d..b374ca7633 100644
--- a/src/core/lib/security/transport/handshake.c
+++ b/src/core/lib/security/transport/handshake.c
@@ -39,8 +39,10 @@
#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
@@ -60,13 +62,16 @@ typedef struct {
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, bool success);
+ void *setup,
+ grpc_error *error);
static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx, void *setup,
- bool success);
+ grpc_error *error);
static void security_connector_remove_handshake(grpc_security_handshake *h) {
GPR_ASSERT(!h->is_client_side);
@@ -95,16 +100,34 @@ static void security_connector_remove_handshake(grpc_security_handshake *h) {
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,
- int is_success) {
+ grpc_error *error) {
+ grpc_timer_cancel(exec_ctx, &h->timer);
if (!h->is_client_side) {
security_connector_remove_handshake(h);
}
- if (is_success) {
+ 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);
@@ -113,14 +136,8 @@ static void security_handshake_done(grpc_exec_ctx *exec_ctx,
}
h->cb(exec_ctx, h->user_data, GRPC_SECURITY_ERROR, NULL, NULL);
}
- 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);
+ unref_handshake(h);
+ GRPC_ERROR_UNREF(error);
}
static void on_peer_checked(grpc_exec_ctx *exec_ctx, void *user_data,
@@ -130,17 +147,20 @@ static void on_peer_checked(grpc_exec_ctx *exec_ctx, void *user_data,
tsi_frame_protector *protector;
tsi_result result;
if (status != GRPC_SECURITY_OK) {
- gpr_log(GPR_ERROR, "Error checking peer.");
- security_handshake_done(exec_ctx, h, 0);
+ 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) {
- gpr_log(GPR_ERROR, "Frame protector creation failed with error %s.",
- tsi_result_to_string(result));
- security_handshake_done(exec_ctx, h, 0);
+ security_handshake_done(
+ exec_ctx, h,
+ grpc_set_tsi_error_result(
+ GRPC_ERROR_CREATE("Frame protector creation failed"), result));
return;
}
h->secure_endpoint =
@@ -148,7 +168,7 @@ static void on_peer_checked(grpc_exec_ctx *exec_ctx, void *user_data,
h->left_overs.slices, h->left_overs.count);
h->left_overs.count = 0;
h->left_overs.length = 0;
- security_handshake_done(exec_ctx, h, 1);
+ security_handshake_done(exec_ctx, h, GRPC_ERROR_NONE);
return;
}
@@ -157,9 +177,9 @@ static void check_peer(grpc_exec_ctx *exec_ctx, grpc_security_handshake *h) {
tsi_result result = tsi_handshaker_extract_peer(h->handshaker, &peer);
if (result != TSI_OK) {
- gpr_log(GPR_ERROR, "Peer extraction failed with error %s",
- tsi_result_to_string(result));
- security_handshake_done(exec_ctx, h, 0);
+ 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,
@@ -185,9 +205,9 @@ static void send_handshake_bytes_to_peer(grpc_exec_ctx *exec_ctx,
} while (result == TSI_INCOMPLETE_DATA);
if (result != TSI_OK) {
- gpr_log(GPR_ERROR, "Handshake failed with error %s",
- tsi_result_to_string(result));
- security_handshake_done(exec_ctx, h, 0);
+ security_handshake_done(exec_ctx, h,
+ grpc_set_tsi_error_result(
+ GRPC_ERROR_CREATE("Handshake failed"), result));
return;
}
@@ -203,7 +223,7 @@ static void send_handshake_bytes_to_peer(grpc_exec_ctx *exec_ctx,
static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx,
void *handshake,
- bool success) {
+ grpc_error *error) {
grpc_security_handshake *h = handshake;
size_t consumed_slice_size = 0;
tsi_result result = TSI_OK;
@@ -211,9 +231,10 @@ static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx,
size_t num_left_overs;
int has_left_overs_in_current_slice = 0;
- if (!success) {
- gpr_log(GPR_ERROR, "Read failed.");
- security_handshake_done(exec_ctx, h, 0);
+ if (error != GRPC_ERROR_NONE) {
+ security_handshake_done(
+ exec_ctx, h,
+ GRPC_ERROR_CREATE_REFERENCING("Handshake read failed", &error, 1));
return;
}
@@ -238,9 +259,9 @@ static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx,
}
if (result != TSI_OK) {
- gpr_log(GPR_ERROR, "Handshake failed with error %s",
- tsi_result_to_string(result));
- security_handshake_done(exec_ctx, h, 0);
+ security_handshake_done(exec_ctx, h,
+ grpc_set_tsi_error_result(
+ GRPC_ERROR_CREATE("Handshake failed"), result));
return;
}
@@ -270,13 +291,15 @@ static void on_handshake_data_received_from_peer(grpc_exec_ctx *exec_ctx,
/* If handshake is NULL, the handshake is done. */
static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx,
- void *handshake, bool success) {
+ void *handshake, grpc_error *error) {
grpc_security_handshake *h = handshake;
/* Make sure that write is OK. */
- if (!success) {
- gpr_log(GPR_ERROR, "Write failed.");
- if (handshake != NULL) security_handshake_done(exec_ctx, h, 0);
+ if (error != GRPC_ERROR_NONE) {
+ if (handshake != NULL)
+ security_handshake_done(
+ exec_ctx, h,
+ GRPC_ERROR_CREATE_REFERENCING("Handshake write failed", &error, 1));
return;
}
@@ -291,13 +314,19 @@ static void on_handshake_data_sent_to_peer(grpc_exec_ctx *exec_ctx,
}
}
-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,
- grpc_security_handshake_done_cb cb,
- void *user_data) {
+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_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));
@@ -309,6 +338,7 @@ void grpc_do_security_handshake(grpc_exec_ctx *exec_ctx,
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,
@@ -327,6 +357,8 @@ void grpc_do_security_handshake(grpc_exec_ctx *exec_ctx,
gpr_mu_unlock(&server_connector->mu);
}
send_handshake_bytes_to_peer(exec_ctx, h);
+ grpc_timer_init(exec_ctx, &h->timer, deadline, on_timeout, h,
+ gpr_now(deadline.clock_type));
}
void grpc_security_handshake_shutdown(grpc_exec_ctx *exec_ctx,