static void on_underlying_io_bytes_received()

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;
            }
        }

    }
}