in source/windows/secure_channel_tls_handler.c [604:761]
static int s_do_server_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 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,
};
sc_handler->read_extra = 0;
sc_handler->estimated_incomplete_size = 0;
SECURITY_STATUS status = AcceptSecurityContext(
&sc_handler->creds,
&sc_handler->sec_handle,
&input_buffers_desc,
sc_handler->ctx_req,
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) {
AWS_LOGF_TRACE(
AWS_LS_IO_TLS, "id=%p: Last processed buffer was incomplete, waiting on more data.", (void *)handler);
sc_handler->estimated_incomplete_size = input_buffers[1].cbBuffer;
return aws_raise_error(AWS_IO_READ_WOULD_BLOCK);
};
/* any output buffers that were filled in with SECBUFFER_TOKEN need to be sent,
SECBUFFER_EXTRA means we need to account for extra data and shift everything for the next run. */
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 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", (void *)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 query of the sizes so future calls to encrypt will be loaded. */
s_message_overhead(handler);
/*
grab the negotiated protocol out of the session.
*/
#ifdef SECBUFFER_APPLICATION_PROTOCOLS
if (sc_handler->alpn_list && aws_tls_is_alpn_available()) {
SecPkgContext_ApplicationProtocol alpn_result;
status = QueryContextAttributes(&sc_handler->sec_handle, SECPKG_ATTR_APPLICATION_PROTOCOL, &alpn_result);
AWS_LOGF_TRACE(AWS_LS_IO_TLS, "id=%p: ALPN is configured. Checking for negotiated protocol", handler);
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
sc_handler->s_connection_state_fn = s_do_application_data_decrypt;
AWS_LOGF_DEBUG(AWS_LS_IO_TLS, "id=%p: TLS handshake completed successfully.", (void *)handler);
s_on_negotiation_success(handler);
}
return AWS_OP_SUCCESS;
}