From 622fc7c76dd29454a052a8f8364a54ca8e28994e Mon Sep 17 00:00:00 2001 From: Steve Kim Date: Thu, 24 Oct 2024 09:04:22 -0700 Subject: [PATCH] cleaner passing of tls related pointers and initial tls_result handling for nw_socket --- .../io/private/tls_channel_handler_shared.h | 7 ++ include/aws/io/socket.h | 3 +- source/channel_bootstrap.c | 19 ++++- source/darwin/nw_socket.c | 78 +++++++++++++++---- 4 files changed, 89 insertions(+), 18 deletions(-) diff --git a/include/aws/io/private/tls_channel_handler_shared.h b/include/aws/io/private/tls_channel_handler_shared.h index faf7e43b4..59d95ee20 100644 --- a/include/aws/io/private/tls_channel_handler_shared.h +++ b/include/aws/io/private/tls_channel_handler_shared.h @@ -25,6 +25,13 @@ enum aws_tls_handler_read_state { AWS_TLS_HANDLER_READ_SHUT_DOWN_COMPLETE, }; +struct tls_connection_context { + struct aws_string *host_name; + struct aws_tls_ctx *tls_ctx; + aws_tls_on_negotiation_result_fn *user_on_negotiation_result; + void *user_on_negotiation_result_user_data; +}; + AWS_EXTERN_C_BEGIN AWS_IO_API void aws_tls_channel_handler_shared_init( diff --git a/include/aws/io/socket.h b/include/aws/io/socket.h index 5bb6e7718..12745f20a 100644 --- a/include/aws/io/socket.h +++ b/include/aws/io/socket.h @@ -62,6 +62,7 @@ struct aws_socket_options { struct aws_socket; struct aws_event_loop; +struct tls_connection_context; /** * Called in client mode when an outgoing connection has succeeded or an error has occurred. @@ -80,7 +81,7 @@ struct aws_tls_connection_options; * the setup of TLS related parameters at creation of the connection as its internal framework * handles both the socket connection and the TLS handshake. */ -typedef void(aws_socket_retrieve_tls_options_fn)(struct aws_tls_connection_options **tls_ctx_options, void *user_data); +typedef void(aws_socket_retrieve_tls_options_fn)(struct tls_connection_context *context, void *user_data); /** * Called by a listening socket when either an incoming connection has been received or an error occurred. diff --git a/source/channel_bootstrap.c b/source/channel_bootstrap.c index 8acfe3e70..625100be2 100644 --- a/source/channel_bootstrap.c +++ b/source/channel_bootstrap.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -636,9 +637,13 @@ static void s_on_client_connection_established(struct aws_socket *socket, int er /* Called when a socket connection attempt requires access to TLS options. Currently this is only necessary on * iOS/tvOS where the parameters used to create the Apple Network Framework socket requires TLS options. */ -static void s_retrieve_tls_options(struct aws_tls_connection_options **tls_ctx_options, void *user_data) { +static void s_retrieve_tls_options(struct tls_connection_context *context, void *user_data) { struct client_connection_args *connection_args = user_data; - *tls_ctx_options = &connection_args->channel_data.tls_options; + AWS_ZERO_STRUCT(context); + context->host_name = connection_args->channel_data.tls_options.server_name; + context->tls_ctx = connection_args->channel_data.tls_options.ctx; + context->user_on_negotiation_result = connection_args->channel_data.user_on_negotiation_result; + context->user_on_negotiation_result_user_data = connection_args->channel_data.tls_user_data; } struct connection_task_data { @@ -1165,6 +1170,10 @@ static void s_tls_server_on_error( } } +/* AWS_USE_SECITEM is using Apple Network Framework's implementation of TLS handling. + * The TCP and TLS handshake are both handled by the network parameters and its options and verification block. + * We do not need to set up a separate TLS slot in the channel for iOS. */ +#if !defined(AWS_USE_SECITEM) static inline int s_setup_server_tls(struct server_channel_data *channel_data, struct aws_channel *channel) { struct aws_channel_slot *tls_slot = NULL; struct aws_channel_handler *tls_handler = NULL; @@ -1248,6 +1257,7 @@ static inline int s_setup_server_tls(struct server_channel_data *channel_data, s return AWS_OP_SUCCESS; } +#endif /* !AWS_USE_SECITEM */ static void s_on_server_channel_on_setup_completed(struct aws_channel *channel, int error_code, void *user_data) { struct server_channel_data *channel_data = user_data; @@ -1313,6 +1323,10 @@ static void s_on_server_channel_on_setup_completed(struct aws_channel *channel, goto error; } + /* AWS_USE_SECITEM is using Apple Network Framework's implementation of TLS handling. + * The TCP and TLS handshake are both handled by the network parameters and its options and verification block. + * We do not need to set up a separate TLS slot in the channel for iOS. */ +#if !defined(AWS_USE_SECITEM) if (channel_data->server_connection_args->use_tls) { /* incoming callback will be invoked upon the negotiation completion so don't do it * here. */ @@ -1323,6 +1337,7 @@ static void s_on_server_channel_on_setup_completed(struct aws_channel *channel, } else { s_server_incoming_callback(channel_data, AWS_OP_SUCCESS, channel); } +#endif /* !AWS_USE_SECITEM */ return; error: diff --git a/source/darwin/nw_socket.c b/source/darwin/nw_socket.c index 3e0be7e03..2bb53246a 100644 --- a/source/darwin/nw_socket.c +++ b/source/darwin/nw_socket.c @@ -105,6 +105,7 @@ static int s_determine_socket_error(int error) { // return AWS_IO_TLS_INVALID_CERTIFICATE_CHAIN; case errSSLHostNameMismatch: // return AWS_IO_TLS_HOST_NAME_MISSMATCH; + case errSecNotTrusted: return AWS_IO_TLS_ERROR_NEGOTIATION_FAILURE; default: @@ -188,6 +189,8 @@ struct nw_socket { struct nw_socket_timeout_args *timeout_args; aws_socket_on_connection_result_fn *on_connection_result_fn; void *connect_accept_user_data; + aws_tls_on_negotiation_result_fn *on_tls_negotiation_result_fn; + void *on_tls_negotiation_result_user_data; struct aws_string *host_name; struct aws_tls_ctx *tls_ctx; @@ -325,6 +328,7 @@ static int s_setup_socket_params(struct nw_socket *nw_socket, const struct aws_s } CFErrorRef error = NULL; + int error_code = AWS_ERROR_SUCCESS; SecTrustRef trust_ref = sec_trust_copy_ref(trust); OSStatus status; bool verification_successful = false; @@ -411,8 +415,16 @@ static int s_setup_socket_params(struct nw_socket *nw_socket, const struct aws_s verification_done: CFRelease(trust_ref); if (error) { + error_code = CFErrorGetCode(error); + error_code = s_determine_socket_error(error_code); + nw_socket->last_error = error_code; + aws_raise_error(error_code); CFRelease(error); } + // DEBUG WIP trigger the on_negotiation_result func w/error here? + if (nw_socket->on_tls_negotiation_result_fn) { + // nw_socket->on_tls_negotiation_result_fn(NULL, NULL, error_code, NULL); + } complete(verification_successful); }, dispatch_loop->dispatch_queue); @@ -645,7 +657,6 @@ int aws_socket_init(struct aws_socket *socket, struct aws_allocator *alloc, cons aws_ref_count_init(&nw_socket->ref_count, nw_socket, s_socket_impl_destroy); - nw_socket->allocator = alloc; aws_linked_list_init(&nw_socket->read_queue); return AWS_OP_SUCCESS; @@ -762,7 +773,7 @@ static void s_schedule_on_readable(struct nw_socket *nw_socket, int error_code, aws_mutex_unlock(&nw_socket->synced_data.lock); } -static void s_process_connection_success_task(struct aws_task *task, void *arg, enum aws_task_status status) { +static void s_process_connection_result_task(struct aws_task *task, void *arg, enum aws_task_status status) { (void)status; struct nw_socket_scheduled_task_args *task_args = arg; @@ -781,7 +792,7 @@ static void s_process_connection_success_task(struct aws_task *task, void *arg, aws_mem_release(task_args->allocator, task_args); } -static void s_schedule_on_connection_success(struct nw_socket *nw_socket, int error_code) { +static void s_schedule_on_connection_result(struct nw_socket *nw_socket, int error_code) { aws_mutex_lock(&nw_socket->synced_data.lock); struct aws_socket *socket = nw_socket->synced_data.base_socket; @@ -795,12 +806,13 @@ static void s_schedule_on_connection_success(struct nw_socket *nw_socket, int er args->allocator = socket->allocator; args->error_code = error_code; aws_ref_count_acquire(&nw_socket->ref_count); - aws_task_init(task, s_process_connection_success_task, args, "connectionSuccessTask"); + aws_task_init(task, s_process_connection_result_task, args, "connectionSuccessTask"); aws_event_loop_schedule_task_now(nw_socket->synced_data.event_loop, task); } aws_mutex_unlock(&nw_socket->synced_data.lock); } +// DEBUG WIP might need to schedule a tls_result the same way we schedule a connection_result() static void s_process_listener_success_task(struct aws_task *task, void *args, enum aws_task_status status) { (void)status; @@ -1015,30 +1027,63 @@ static int s_socket_connect_fn( return aws_raise_error(AWS_IO_EVENT_LOOP_ALREADY_ASSIGNED); } - struct aws_tls_connection_options *tls_connection_options = NULL; + struct tls_connection_context tls_connection_context; if (retrieve_tls_options != NULL) { - retrieve_tls_options(&tls_connection_options, user_data); - if (tls_connection_options->server_name) { + retrieve_tls_options(&tls_connection_context, user_data); + if (tls_connection_context.host_name != NULL) { if (nw_socket->host_name != NULL) { aws_string_destroy(nw_socket->host_name); nw_socket->host_name = NULL; } nw_socket->host_name = aws_string_new_from_string( - tls_connection_options->server_name->allocator, tls_connection_options->server_name); + tls_connection_context.host_name->allocator, tls_connection_context.host_name); if (nw_socket->host_name == NULL) { return AWS_OP_ERR; } } - if (tls_connection_options->ctx) { + if (tls_connection_context.tls_ctx) { if (nw_socket->tls_ctx) { aws_tls_ctx_release(nw_socket->tls_ctx); nw_socket->tls_ctx = NULL; } - nw_socket->tls_ctx = tls_connection_options->ctx; + nw_socket->tls_ctx = tls_connection_context.tls_ctx; aws_tls_ctx_acquire(nw_socket->tls_ctx); } - } + + nw_socket->on_tls_negotiation_result_fn = tls_connection_context.user_on_negotiation_result; + nw_socket->on_tls_negotiation_result_user_data = tls_connection_context.user_on_negotiation_result_user_data; + } + /* + struct aws_tls_connection_options *tls_connection_options = NULL; + if (retrieve_tls_options != NULL) { + retrieve_tls_options(&tls_connection_options, user_data); + if (tls_connection_options->server_name) { + if (nw_socket->host_name != NULL) { + aws_string_destroy(nw_socket->host_name); + nw_socket->host_name = NULL; + } + nw_socket->host_name = aws_string_new_from_string( + tls_connection_options->server_name->allocator, tls_connection_options->server_name); + if (nw_socket->host_name == NULL) { + return AWS_OP_ERR; + } + } + + if (tls_connection_options->ctx) { + if (nw_socket->tls_ctx) { + aws_tls_ctx_release(nw_socket->tls_ctx); + nw_socket->tls_ctx = NULL; + } + nw_socket->tls_ctx = tls_connection_options->ctx; + aws_tls_ctx_acquire(nw_socket->tls_ctx); + } + + if (tls_connection_options->on_negotiation_result) { + nw_socket->on_tls_negotiation_result_fn = tls_connection_options->on_negotiation_result; + } + } + */ aws_mutex_lock(&nw_socket->synced_data.lock); nw_socket->synced_data.event_loop = event_loop; @@ -1210,7 +1255,7 @@ static int s_socket_connect_fn( socket->state = CONNECTED_WRITE | CONNECTED_READ; nw_socket->setup_run = true; aws_ref_count_acquire(&nw_socket->ref_count); - s_schedule_on_connection_success(nw_socket, AWS_OP_SUCCESS); + s_schedule_on_connection_result(nw_socket, AWS_OP_SUCCESS); s_schedule_next_read(nw_socket); aws_ref_count_release(&nw_socket->ref_count); @@ -1233,7 +1278,10 @@ static int s_socket_connect_fn( aws_raise_error(error_code); socket->state = ERROR; if (!nw_socket->setup_run) { - s_schedule_on_connection_success(nw_socket, error_code); + s_schedule_on_connection_result(nw_socket, error_code); + // DEBUG WIP we need to call the Tls handler callback from tls_ctx + // Maybe schedule this from within the verification block where the TLS handhake error is origianting + // s_schedule_on_negotiation_result() nw_socket->setup_run = true; } else if (socket->readable_fn) { s_schedule_on_readable(nw_socket, nw_socket->last_error, NULL); @@ -1255,7 +1303,7 @@ static int s_socket_connect_fn( socket->state = CLOSED; aws_raise_error(AWS_IO_SOCKET_CLOSED); if (!nw_socket->setup_run) { - s_schedule_on_connection_success(nw_socket, AWS_IO_SOCKET_CLOSED); + s_schedule_on_connection_result(nw_socket, AWS_IO_SOCKET_CLOSED); nw_socket->setup_run = true; } else if (socket->readable_fn) { s_schedule_on_readable(nw_socket, AWS_IO_SOCKET_CLOSED, NULL); @@ -1507,7 +1555,7 @@ static int s_socket_start_accept_fn( } else if (state == nw_listener_state_ready) { AWS_LOGF_DEBUG( AWS_LS_IO_SOCKET, - "id=%p handle=%p: lisnter on port ready ", + "id=%p handle=%p: listener on port ready ", (void *)socket, (void *)nw_socket->nw_connection);