in source/windows/secure_channel_tls_handler.c [880:1046]
static int s_do_client_side_negotiation_step_2(struct aws_channel_handler *handler) {
struct secure_channel_handler *sc_handler = handler->impl;
AWS_LOGF_TRACE(
AWS_LS_IO_TLS,
"id=%p: running step 2 of client-side negotiation (cipher change, key exchange etc...)",
(void *)handler);
SecBuffer input_buffers[] = {
[0] =
{
.pvBuffer = sc_handler->buffered_read_in_data_buf.buffer,
.cbBuffer = (unsigned long)sc_handler->buffered_read_in_data_buf.len,
.BufferType = SECBUFFER_TOKEN,
},
[1] =
{
.pvBuffer = NULL,
.cbBuffer = 0,
.BufferType = SECBUFFER_EMPTY,
},
};
SecBufferDesc input_buffers_desc = {
.ulVersion = SECBUFFER_VERSION,
.cBuffers = 2,
.pBuffers = input_buffers,
};
SecBuffer output_buffers[3];
AWS_ZERO_ARRAY(output_buffers);
output_buffers[0].BufferType = SECBUFFER_TOKEN;
output_buffers[1].BufferType = SECBUFFER_ALERT;
SecBufferDesc output_buffers_desc = {
.ulVersion = SECBUFFER_VERSION,
.cBuffers = 3,
.pBuffers = output_buffers,
};
SECURITY_STATUS status = SEC_E_OK;
sc_handler->read_extra = 0;
sc_handler->estimated_incomplete_size = 0;
char server_name_cstr[256];
AWS_ZERO_ARRAY(server_name_cstr);
AWS_FATAL_ASSERT(sc_handler->server_name.len < sizeof(server_name_cstr));
memcpy(server_name_cstr, sc_handler->server_name.buffer, sc_handler->server_name.len);
status = InitializeSecurityContextA(
&sc_handler->creds,
&sc_handler->sec_handle,
(SEC_CHAR *)server_name_cstr,
sc_handler->ctx_req,
0,
0,
&input_buffers_desc,
0,
NULL,
&output_buffers_desc,
&sc_handler->ctx_ret_flags,
&sc_handler->sspi_timestamp);
if (status != SEC_E_INCOMPLETE_MESSAGE && status != SEC_I_CONTINUE_NEEDED && status != SEC_E_OK) {
AWS_LOGF_ERROR(
AWS_LS_IO_TLS, "id=%p: Error during negotiation. SECURITY_STATUS is %d", (void *)handler, (int)status);
int aws_error = s_determine_sspi_error(status);
aws_raise_error(aws_error);
s_invoke_negotiation_error(handler, aws_error);
return AWS_OP_ERR;
}
if (status == SEC_E_INCOMPLETE_MESSAGE) {
sc_handler->estimated_incomplete_size = input_buffers[1].cbBuffer;
AWS_LOGF_TRACE(
AWS_LS_IO_TLS,
"id=%p: Incomplete buffer recieved. Incomplete size is %zu. Waiting for more data.",
(void *)handler,
sc_handler->estimated_incomplete_size);
return aws_raise_error(AWS_IO_READ_WOULD_BLOCK);
}
if (status == SEC_I_CONTINUE_NEEDED || status == SEC_E_OK) {
for (size_t i = 0; i < output_buffers_desc.cBuffers; ++i) {
SecBuffer *buf_ptr = &output_buffers[i];
if (buf_ptr->BufferType == SECBUFFER_TOKEN && buf_ptr->cbBuffer) {
struct aws_io_message *outgoing_message = aws_channel_acquire_message_from_pool(
sc_handler->slot->channel, AWS_IO_MESSAGE_APPLICATION_DATA, buf_ptr->cbBuffer);
if (!outgoing_message) {
FreeContextBuffer(buf_ptr->pvBuffer);
s_invoke_negotiation_error(handler, aws_last_error());
return AWS_OP_ERR;
}
memcpy(outgoing_message->message_data.buffer, buf_ptr->pvBuffer, buf_ptr->cbBuffer);
outgoing_message->message_data.len = buf_ptr->cbBuffer;
FreeContextBuffer(buf_ptr->pvBuffer);
if (aws_channel_slot_send_message(sc_handler->slot, outgoing_message, AWS_CHANNEL_DIR_WRITE)) {
aws_mem_release(outgoing_message->allocator, outgoing_message);
s_invoke_negotiation_error(handler, aws_last_error());
return AWS_OP_ERR;
}
}
}
if (input_buffers[1].BufferType == SECBUFFER_EXTRA && input_buffers[1].cbBuffer > 0) {
AWS_LOGF_TRACE(
AWS_LS_IO_TLS,
"id=%p: Extra data recieved. Extra data size is %lu.",
(void *)handler,
input_buffers[1].cbBuffer);
sc_handler->read_extra = input_buffers[1].cbBuffer;
}
}
if (status == SEC_E_OK) {
AWS_LOGF_TRACE(AWS_LS_IO_TLS, "id=%p: handshake completed", handler);
/* if a custom CA store was configured, we have to do the verification ourselves. */
if (sc_handler->custom_ca_store) {
AWS_LOGF_TRACE(
AWS_LS_IO_TLS,
"id=%p: Custom CA was configured, evaluating trust before completing connection",
(void *)handler);
if (s_manually_verify_peer_cert(handler)) {
aws_raise_error(AWS_IO_TLS_ERROR_NEGOTIATION_FAILURE);
s_invoke_negotiation_error(handler, AWS_IO_TLS_ERROR_NEGOTIATION_FAILURE);
return AWS_OP_ERR;
}
}
sc_handler->negotiation_finished = true;
/* force the sizes query, so future Encrypt message calls work.*/
s_message_overhead(handler);
#ifdef SECBUFFER_APPLICATION_PROTOCOLS
if (sc_handler->alpn_list && aws_tls_is_alpn_available()) {
AWS_LOGF_TRACE(AWS_LS_IO_TLS, "id=%p: Retrieving negotiated protocol.", handler);
SecPkgContext_ApplicationProtocol alpn_result;
status = QueryContextAttributes(&sc_handler->sec_handle, SECPKG_ATTR_APPLICATION_PROTOCOL, &alpn_result);
if (status == SEC_E_OK && alpn_result.ProtoNegoStatus == SecApplicationProtocolNegotiationStatus_Success) {
aws_byte_buf_init(&sc_handler->protocol, handler->alloc, alpn_result.ProtocolIdSize + 1);
memset(sc_handler->protocol.buffer, 0, alpn_result.ProtocolIdSize + 1);
memcpy(sc_handler->protocol.buffer, alpn_result.ProtocolId, alpn_result.ProtocolIdSize);
sc_handler->protocol.len = alpn_result.ProtocolIdSize;
AWS_LOGF_DEBUG(
AWS_LS_IO_TLS, "id=%p: Negotiated protocol %s", handler, (char *)sc_handler->protocol.buffer);
} else {
AWS_LOGF_WARN(
AWS_LS_IO_TLS,
"id=%p: Error retrieving negotiated protocol. SECURITY_STATUS is %d",
handler,
(int)status);
int aws_error = s_determine_sspi_error(status);
aws_raise_error(aws_error);
}
}
#endif
AWS_LOGF_DEBUG(AWS_LS_IO_TLS, "id=%p: TLS handshake completed successfully.", (void *)handler);
sc_handler->s_connection_state_fn = s_do_application_data_decrypt;
s_on_negotiation_success(handler);
}
return AWS_OP_SUCCESS;
}