in adapters/tlsio_schannel.c [613:1038]
static void on_underlying_io_bytes_received(void* context, const unsigned char* buffer, size_t size)
{
TLS_IO_INSTANCE* tls_io_instance = (TLS_IO_INSTANCE*)context;
size_t consumed_bytes;
if (resize_receive_buffer(tls_io_instance, tls_io_instance->received_byte_count + size) == 0)
{
(void)memcpy(tls_io_instance->received_bytes + tls_io_instance->received_byte_count, buffer, size);
tls_io_instance->received_byte_count += size;
if (size > tls_io_instance->needed_bytes)
{
tls_io_instance->needed_bytes = 0;
}
else
{
tls_io_instance->needed_bytes -= size;
}
/* Drain what we received */
while (tls_io_instance->needed_bytes == 0)
{
if ((tls_io_instance->tlsio_state == TLSIO_STATE_HANDSHAKE_CLIENT_HELLO_SENT) ||
(tls_io_instance->tlsio_state == TLSIO_STATE_RENEGOTIATE))
{
SecBuffer input_buffers[2];
SecBuffer output_buffers[2];
SecBufferDesc input_buffers_desc;
SecBufferDesc output_buffers_desc;
SECURITY_STATUS status;
unsigned long flags;
ULONG context_attributes;
/* we need to try and perform the second (next) step of the init */
input_buffers[0].cbBuffer = (unsigned long)tls_io_instance->received_byte_count;
input_buffers[0].BufferType = SECBUFFER_TOKEN;
input_buffers[0].pvBuffer = (void*)tls_io_instance->received_bytes;
input_buffers[1].cbBuffer = 0;
input_buffers[1].BufferType = SECBUFFER_EMPTY;
input_buffers[1].pvBuffer = 0;
input_buffers_desc.cBuffers = 2;
input_buffers_desc.pBuffers = input_buffers;
input_buffers_desc.ulVersion = SECBUFFER_VERSION;
output_buffers[0].cbBuffer = 0;
output_buffers[0].BufferType = SECBUFFER_TOKEN;
output_buffers[0].pvBuffer = NULL;
output_buffers[1].cbBuffer = 0;
output_buffers[1].BufferType = SECBUFFER_EMPTY;
output_buffers[1].pvBuffer = 0;
output_buffers_desc.cBuffers = 2;
output_buffers_desc.pBuffers = output_buffers;
output_buffers_desc.ulVersion = SECBUFFER_VERSION;
flags = ISC_REQ_EXTENDED_ERROR | ISC_REQ_STREAM | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_USE_SUPPLIED_CREDS;
status = InitializeSecurityContext(&tls_io_instance->credential_handle,
&tls_io_instance->security_context, tls_io_instance->host_name, flags, 0, 0, &input_buffers_desc, 0,
&tls_io_instance->security_context, &output_buffers_desc,
&context_attributes, NULL);
switch (status)
{
case SEC_E_INCOMPLETE_MESSAGE:
if (input_buffers[1].BufferType != SECBUFFER_MISSING)
{
//If SECBUFFER_MISSING not sent, try to read byte by byte.
tls_io_instance->needed_bytes = 1;
}
else
{
tls_io_instance->needed_bytes = input_buffers[1].cbBuffer;
}
if (resize_receive_buffer(tls_io_instance, tls_io_instance->received_byte_count + tls_io_instance->needed_bytes) != 0)
{
tls_io_instance->tlsio_state = TLSIO_STATE_ERROR;
if (tls_io_instance->on_io_open_complete != NULL)
{
tls_io_instance->on_io_open_complete(tls_io_instance->on_io_open_complete_context, IO_OPEN_ERROR);
}
}
break;
case SEC_E_OK:
consumed_bytes = tls_io_instance->received_byte_count;
/* Any extra bytes left over or did we fully consume the receive buffer? */
if (input_buffers[1].BufferType == SECBUFFER_EXTRA)
{
consumed_bytes -= input_buffers[1].cbBuffer;
(void)memmove(tls_io_instance->received_bytes, tls_io_instance->received_bytes + consumed_bytes, tls_io_instance->received_byte_count - consumed_bytes);
}
tls_io_instance->received_byte_count -= consumed_bytes;
/* if nothing more to consume, set the needed bytes to 1, to get on the next byte how many we actually need */
tls_io_instance->needed_bytes = tls_io_instance->received_byte_count == 0 ? 1 : 0;
if (verify_custom_certificate_if_needed(tls_io_instance) != 0)
{
LogError("Unable to verify server certificate against custom server trusted certificate");
if (tls_io_instance->on_io_open_complete != NULL)
{
tls_io_instance->on_io_open_complete(tls_io_instance->on_io_open_complete_context, IO_OPEN_ERROR);
}
}
else if (set_receive_buffer(tls_io_instance, tls_io_instance->needed_bytes + tls_io_instance->received_byte_count) != 0)
{
tls_io_instance->tlsio_state = TLSIO_STATE_ERROR;
if (tls_io_instance->on_io_open_complete != NULL)
{
tls_io_instance->on_io_open_complete(tls_io_instance->on_io_open_complete_context, IO_OPEN_ERROR);
}
}
else
{
if (tls_io_instance->tlsio_state == TLSIO_STATE_HANDSHAKE_CLIENT_HELLO_SENT)
{
tls_io_instance->tlsio_state = TLSIO_STATE_OPEN;
if (tls_io_instance->on_io_open_complete != NULL)
{
tls_io_instance->on_io_open_complete(tls_io_instance->on_io_open_complete_context, IO_OPEN_OK);
}
}
else
{
LIST_ITEM_HANDLE first_pending_io;
tls_io_instance->tlsio_state = TLSIO_STATE_OPEN;
first_pending_io = singlylinkedlist_get_head_item(tls_io_instance->pending_io_list);
while (first_pending_io != NULL)
{
PENDING_SEND* pending_send = (PENDING_SEND*)singlylinkedlist_item_get_value(first_pending_io);
if (pending_send == NULL)
{
LogError("Failure: retrieving pending IO from list");
indicate_error(tls_io_instance);
break;
}
else
{
if (internal_send(tls_io_instance, pending_send->bytes, pending_send->length, pending_send->on_send_complete, pending_send->on_send_complete_context) != 0)
{
LogError("send failed");
indicate_error(tls_io_instance);
}
else
{
if (singlylinkedlist_remove(tls_io_instance->pending_io_list, first_pending_io) != 0)
{
LogError("Failure: removing pending IO from list");
indicate_error(tls_io_instance);
}
}
first_pending_io = singlylinkedlist_get_head_item(tls_io_instance->pending_io_list);
}
}
}
}
break;
case SEC_I_COMPLETE_NEEDED:
case SEC_I_CONTINUE_NEEDED:
case SEC_I_COMPLETE_AND_CONTINUE:
if ((output_buffers[0].cbBuffer > 0) && xio_send(tls_io_instance->socket_io, output_buffers[0].pvBuffer, output_buffers[0].cbBuffer, unchecked_on_send_complete, NULL) != 0)
{
tls_io_instance->tlsio_state = TLSIO_STATE_ERROR;
if (tls_io_instance->on_io_open_complete != NULL)
{
tls_io_instance->on_io_open_complete(tls_io_instance->on_io_open_complete_context, IO_OPEN_ERROR);
}
}
else
{
consumed_bytes = tls_io_instance->received_byte_count;
/* Any extra bytes left over or did we fully consume the receive buffer? */
if (input_buffers[1].BufferType == SECBUFFER_EXTRA)
{
consumed_bytes -= input_buffers[1].cbBuffer;
(void)memmove(tls_io_instance->received_bytes, tls_io_instance->received_bytes + consumed_bytes, tls_io_instance->received_byte_count - consumed_bytes);
}
tls_io_instance->received_byte_count -= consumed_bytes;
/* if nothing more to consume, set the needed bytes to 1, to get on the next byte how many we actually need */
tls_io_instance->needed_bytes = tls_io_instance->received_byte_count == 0 ? 1 : 0;
if (set_receive_buffer(tls_io_instance, tls_io_instance->needed_bytes + tls_io_instance->received_byte_count) != 0)
{
tls_io_instance->tlsio_state = TLSIO_STATE_ERROR;
if (tls_io_instance->on_io_open_complete != NULL)
{
tls_io_instance->on_io_open_complete(tls_io_instance->on_io_open_complete_context, IO_OPEN_ERROR);
}
}
else
{
if (tls_io_instance->tlsio_state != TLSIO_STATE_RENEGOTIATE)
{
tls_io_instance->tlsio_state = TLSIO_STATE_HANDSHAKE_CLIENT_HELLO_SENT;
}
}
}
break;
case SEC_E_UNTRUSTED_ROOT:
tls_io_instance->tlsio_state = TLSIO_STATE_ERROR;
if (tls_io_instance->on_io_open_complete != NULL)
{
tls_io_instance->on_io_open_complete(tls_io_instance->on_io_open_complete_context, IO_OPEN_ERROR);
}
break;
default:
{
LPVOID srcText = NULL;
if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
status, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&srcText, 0, NULL) > 0)
{
LogError("[%#x] %s", status, (LPTSTR)srcText);
LocalFree(srcText);
}
else
{
LogError("[%#x]", status);
}
tls_io_instance->tlsio_state = TLSIO_STATE_ERROR;
indicate_error(tls_io_instance);
}
break;
}
if (output_buffers[0].pvBuffer != NULL)
{
FreeContextBuffer(output_buffers[0].pvBuffer);
output_buffers[0].pvBuffer = NULL;
}
if (output_buffers[1].pvBuffer != NULL)
{
FreeContextBuffer(output_buffers[1].pvBuffer);
output_buffers[1].pvBuffer = NULL;
}
}
else if (tls_io_instance->tlsio_state == TLSIO_STATE_OPEN)
{
SecBuffer security_buffers[4];
SecBufferDesc security_buffers_desc;
SECURITY_STATUS status;
security_buffers[0].BufferType = SECBUFFER_DATA;
security_buffers[0].pvBuffer = tls_io_instance->received_bytes;
security_buffers[0].cbBuffer = (unsigned long)tls_io_instance->received_byte_count;
security_buffers[1].BufferType = SECBUFFER_EMPTY;
security_buffers[2].BufferType = SECBUFFER_EMPTY;
security_buffers[3].BufferType = SECBUFFER_EMPTY;
security_buffers_desc.cBuffers = sizeof(security_buffers) / sizeof(security_buffers[0]);
security_buffers_desc.pBuffers = security_buffers;
security_buffers_desc.ulVersion = SECBUFFER_VERSION;
status = DecryptMessage(&tls_io_instance->security_context, &security_buffers_desc, 0, NULL);
switch (status)
{
case SEC_E_INCOMPLETE_MESSAGE:
if (security_buffers[1].BufferType != SECBUFFER_MISSING)
{
//If SECBUFFER_MISSING not sent, try to read byte by byte.
tls_io_instance->needed_bytes = 1;
}
else
{
tls_io_instance->needed_bytes = security_buffers[1].cbBuffer;
}
if (resize_receive_buffer(tls_io_instance, tls_io_instance->received_byte_count + tls_io_instance->needed_bytes) != 0)
{
tls_io_instance->tlsio_state = TLSIO_STATE_ERROR;
indicate_error(tls_io_instance);
}
break;
case SEC_E_OK:
if (security_buffers[1].BufferType != SECBUFFER_DATA)
{
tls_io_instance->tlsio_state = TLSIO_STATE_ERROR;
indicate_error(tls_io_instance);
}
else
{
size_t i;
/* notify of the received data */
if (tls_io_instance->on_bytes_received != NULL)
{
tls_io_instance->on_bytes_received(tls_io_instance->on_bytes_received_context, (const unsigned char *) security_buffers[1].pvBuffer, security_buffers[1].cbBuffer);
}
consumed_bytes = tls_io_instance->received_byte_count;
for (i = 0; i < sizeof(security_buffers) / sizeof(security_buffers[0]); i++)
{
/* Any extra bytes left over or did we fully consume the receive buffer? */
if (security_buffers[i].BufferType == SECBUFFER_EXTRA)
{
consumed_bytes -= security_buffers[i].cbBuffer;
(void)memmove(tls_io_instance->received_bytes, tls_io_instance->received_bytes + consumed_bytes, tls_io_instance->received_byte_count - consumed_bytes);
break;
}
}
tls_io_instance->received_byte_count -= consumed_bytes;
/* if nothing more to consume, set the needed bytes to 1, to get on the next byte how many we actually need */
tls_io_instance->needed_bytes = tls_io_instance->received_byte_count == 0 ? 1 : 0;
if (set_receive_buffer(tls_io_instance, tls_io_instance->needed_bytes + tls_io_instance->received_byte_count) != 0)
{
tls_io_instance->tlsio_state = TLSIO_STATE_ERROR;
indicate_error(tls_io_instance);
}
}
break;
case SEC_I_RENEGOTIATE:
{
SecBuffer input_buffers[2];
SecBuffer output_buffers[2];
SecBufferDesc input_buffers_desc;
SecBufferDesc output_buffers_desc;
unsigned long flags;
ULONG context_attributes;
/* we need to try and perform the second (next) step of the init */
input_buffers[0].cbBuffer = (unsigned long)tls_io_instance->received_byte_count;
input_buffers[0].BufferType = SECBUFFER_TOKEN;
input_buffers[0].pvBuffer = (void*)tls_io_instance->received_bytes;
input_buffers[1].cbBuffer = 0;
input_buffers[1].BufferType = SECBUFFER_EMPTY;
input_buffers[1].pvBuffer = 0;
input_buffers_desc.cBuffers = 2;
input_buffers_desc.pBuffers = input_buffers;
input_buffers_desc.ulVersion = SECBUFFER_VERSION;
output_buffers[0].cbBuffer = 0;
output_buffers[0].BufferType = SECBUFFER_TOKEN;
output_buffers[0].pvBuffer = NULL;
output_buffers[1].cbBuffer = 0;
output_buffers[1].BufferType = SECBUFFER_EMPTY;
output_buffers[1].pvBuffer = 0;
output_buffers_desc.cBuffers = 2;
output_buffers_desc.pBuffers = output_buffers;
output_buffers_desc.ulVersion = SECBUFFER_VERSION;
flags = ISC_REQ_EXTENDED_ERROR | ISC_REQ_STREAM | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_USE_SUPPLIED_CREDS;
status = InitializeSecurityContext(&tls_io_instance->credential_handle,
&tls_io_instance->security_context, tls_io_instance->host_name, flags, 0, 0, &input_buffers_desc, 0,
&tls_io_instance->security_context, &output_buffers_desc,
&context_attributes, NULL);
if ((status == SEC_I_COMPLETE_NEEDED) || (status == SEC_I_CONTINUE_NEEDED) || (status == SEC_I_COMPLETE_AND_CONTINUE))
{
/* This needs to account for EXTRA */
tls_io_instance->received_byte_count = 0;
if (xio_send(tls_io_instance->socket_io, output_buffers[0].pvBuffer, output_buffers[0].cbBuffer, unchecked_on_send_complete, NULL) != 0)
{
tls_io_instance->tlsio_state = TLSIO_STATE_ERROR;
indicate_error(tls_io_instance);
}
else
{
tls_io_instance->needed_bytes = 1;
if (resize_receive_buffer(tls_io_instance, tls_io_instance->needed_bytes + tls_io_instance->received_byte_count) != 0)
{
tls_io_instance->tlsio_state = TLSIO_STATE_ERROR;
indicate_error(tls_io_instance);
}
else
{
tls_io_instance->tlsio_state = TLSIO_STATE_RENEGOTIATE;
}
}
}
if (output_buffers[0].pvBuffer != NULL)
{
FreeContextBuffer(output_buffers[0].pvBuffer);
output_buffers[0].pvBuffer = NULL;
}
if (output_buffers[1].pvBuffer != NULL)
{
FreeContextBuffer(output_buffers[1].pvBuffer);
output_buffers[1].pvBuffer = NULL;
}
break;
}
default:
{
LPVOID srcText = NULL;
if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
status, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&srcText, 0, NULL) > 0)
{
LogError("[%#x] %s", status, (LPTSTR)srcText);
LocalFree(srcText);
}
else
{
LogError("[%#x]", status);
}
tls_io_instance->tlsio_state = TLSIO_STATE_ERROR;
indicate_error(tls_io_instance);
}
break;
}
}
else
{
/* Received data in error or other state */
break;
}
}
}
}