static void send_client_hello()

in adapters/tlsio_schannel.c [297:403]


static void send_client_hello(TLS_IO_INSTANCE* tls_io_instance)
{
    SecBuffer init_security_buffers[2];
    ULONG context_attributes;
    SECURITY_STATUS status;
    SCHANNEL_CRED auth_data;
    PCCERT_CONTEXT certContext;
    auth_data.dwVersion = SCHANNEL_CRED_VERSION;
    if (tls_io_instance->x509_schannel_handle != NULL)
    {
        certContext = x509_schannel_get_certificate_context(tls_io_instance->x509_schannel_handle);
        auth_data.cCreds = 1;
        auth_data.paCred = &certContext;
    }
    else
    {
        auth_data.cCreds = 0;
        auth_data.paCred = NULL;
    }
    auth_data.hRootStore = NULL;
    auth_data.cSupportedAlgs = 0;
    auth_data.palgSupportedAlgs = NULL;
    auth_data.grbitEnabledProtocols = 0;
    auth_data.dwMinimumCipherStrength = 0;
    auth_data.dwMaximumCipherStrength = 0;
    auth_data.dwSessionLifespan = 0;
#if defined(SCH_USE_STRONG_CRYPTO)
    auth_data.dwFlags = SCH_USE_STRONG_CRYPTO | SCH_CRED_NO_DEFAULT_CREDS;
#else
    auth_data.dwFlags = SCH_CRED_NO_DEFAULT_CREDS;
#endif
    if (tls_io_instance->ignore_server_name_check)
    {
        auth_data.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK;
    }
    auth_data.dwCredFormat = 0;

    if (tls_io_instance->trustedCertificate != NULL)
    {
        // SCH_CRED_MANUAL_CRED_VALIDATION flag signals to schannel to NOT use
        // the Windows certificate store, but instead have application verify
        // certificate.
        auth_data.dwFlags |= SCH_CRED_MANUAL_CRED_VALIDATION;
    }

    status = AcquireCredentialsHandle(NULL, UNISP_NAME, SECPKG_CRED_OUTBOUND, NULL,
        &auth_data, NULL, NULL, &tls_io_instance->credential_handle, NULL);
    if (status != SEC_E_OK)
    {
        tls_io_instance->tlsio_state = TLSIO_STATE_ERROR;
        indicate_error(tls_io_instance);
    }
    else
    {
        SecBufferDesc security_buffers_desc;
        tls_io_instance->credential_handle_allocated = true;

        init_security_buffers[0].cbBuffer = 0;
        init_security_buffers[0].BufferType = SECBUFFER_TOKEN;
        init_security_buffers[0].pvBuffer = NULL;
        init_security_buffers[1].cbBuffer = 0;
        init_security_buffers[1].BufferType = SECBUFFER_EMPTY;
        init_security_buffers[1].pvBuffer = 0;

        security_buffers_desc.cBuffers = 2;
        security_buffers_desc.pBuffers = init_security_buffers;
        security_buffers_desc.ulVersion = SECBUFFER_VERSION;

        status = InitializeSecurityContext(&tls_io_instance->credential_handle,
            NULL, tls_io_instance->host_name, ISC_REQ_EXTENDED_ERROR | ISC_REQ_STREAM | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_USE_SUPPLIED_CREDS, 0, 0, NULL, 0,
            &tls_io_instance->security_context, &security_buffers_desc,
            &context_attributes, NULL);

        if ((status == SEC_I_COMPLETE_NEEDED) || (status == SEC_I_CONTINUE_NEEDED) || (status == SEC_I_COMPLETE_AND_CONTINUE))
        {
            if (xio_send(tls_io_instance->socket_io, init_security_buffers[0].pvBuffer, init_security_buffers[0].cbBuffer, unchecked_on_send_complete, NULL) != 0)
            {
                tls_io_instance->tlsio_state = TLSIO_STATE_ERROR;
                indicate_error(tls_io_instance);
            }
            else
            {
                /* set the needed bytes to 1, to get on the next byte how many we actually need */
                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_HANDSHAKE_CLIENT_HELLO_SENT;
                }
            }
        }

        if (init_security_buffers[0].pvBuffer != NULL)
        {
            FreeContextBuffer(init_security_buffers[0].pvBuffer);
        }

        if (init_security_buffers[1].pvBuffer != NULL)
        {
            FreeContextBuffer(init_security_buffers[1].pvBuffer);
        }
    }
}