Platform SDK: Logon Authentication

Using InitializeSecurityContext

The InitializeSecurityContext function initiates the outbound, client security context from a credential handle. The function establishes a security context between the client application and a remote peer. The InitializeSecurityContext function returns a token that the client must pass to the remote peer, which in turn submits it to the local security implementation through the AcceptSecurityContext call. The token generated is opaque to all callers.

*SecBufferDesc   InBuffer;
SecBuffer       InBuffers[2];
SecBufferDesc   OutBuffer;
SecBuffer       OutBuffers[1];
DWORD           dwSSPIFlags;
DWORD           dwSSPIOutFlags;
TimeStamp       tsExpiry;
SECURITY_STATUS scRet;
DWORD           cbData;

BOOL            fDoRead = FALSE;

dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT   |
              ISC_REQ_REPLAY_DETECT     |
              ISC_REQ_CONFIDENTIALITY   |
              ISC_RET_EXTENDED_ERROR    |
              ISC_REQ_ALLOCATE_MEMORY   |
              ISC_REQ_STREAM;

cbIoBuffer = 0;

scRet = SEC_I_CONTINUE_NEEDED;

while(scRet == SEC_I_CONTINUE_NEEDED        ||
      scRet == SEC_E_INCOMPLETE_MESSAGE     ||
      scRet == SEC_I_INCOMPLETE_CREDENTIALS) 
{

//--------------------------------------------------------------------
// If the i/o buffer is empty, or it contains a fragment of a 
// handshake message, read more data from the server.

if(0 == cbIoBuffer || scRet == SEC_E_INCOMPLETE_MESSAGE)
    {
        if(fDoRead)
        {
            BytesRead = ReadDataFromClient(IoBuffer + cbIoBuffer);
            cbIoBuffer += BytesRead;
        }
        else
        {
            fDoRead = TRUE;
        }
    }

//--------------------------------------------------------------------
// Set up the input buffers. Buffer 0 is used to pass in data
// received from the server. Schannel will consume some or all
// of this. Leftover data (if any) will be placed in buffer 1 and
// given a buffer type of SECBUFFER_EXTRA.

    InBuffers[0].pvBuffer    = IoBuffer;
    InBuffers[0].cbBuffer    = cbIoBuffer;
    InBuffers[0].BufferType  = SECBUFFER_TOKEN;

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

    InBuffer.cBuffers        = 2;
    InBuffer.pBuffers        = InBuffers;
    InBuffer.ulVersion       = SECBUFFER_VERSION;

//--------------------------------------------------------------------
// Set up the output buffers. These are initialized to NULL

    OutBuffers[0].pvBuffer   = NULL;
    OutBuffers[0].BufferType = SECBUFFER_TOKEN;
    OutBuffers[0].cbBuffer   = 0;

    OutBuffer.cBuffers       = 1;
    OutBuffer.pBuffers       = OutBuffers;
    OutBuffer.ulVersion      = SECBUFFER_VERSION;

//--------------------------------------------------------------------
// Call InitializeSecurityContext.

    scRet = g_SecurityFunc.InitializeSecurityContextA(
          phCreds,
          phContext,
          NULL,
          dwSSPIFlags,
          0,
          SECURITY_NATIVE_DREP,
          &InBuffer,
          0,
          NULL,
          &OutBuffer,
          &dwSSPIOutFlags,
          &tsExpiry);

//--------------------------------------------------------------------
// If InitializeSecurityContext was successful (or if the error was 
// one of the special extended ones), send the contents of the output
// buffer to the server.

    if(scRet == SEC_E_OK                ||
       scRet == SEC_I_CONTINUE_NEEDED   ||
       FAILED(scRet) && (dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR))
    {
        if(OutBuffers[0].cbBuffer != 0 && OutBuffers[0].pvBuffer != NULL)
        {
//--------------------------------------------------------------------
// Send response to client if there is one

            SendToClient(OutBuffers[0].pvBuffer,
                         OutBuffers[0].cbBuffer);

//--------------------------------------------------------------------
// Free the output buffer.

            g_SecurityFunc.FreeContextBuffer(OutBuffers[0].pvBuffer);
            OutBuffers[0].pvBuffer = NULL;
        }
    }

//--------------------------------------------------------------------
// If InitializeSecurityContext returned SEC_E_INCOMPLETE_MESSAGE,
// read more data from the server and try again.

    if(scRet == SEC_E_INCOMPLETE_MESSAGE)
    {
        continue;
    }

//--------------------------------------------------------------------
// If InitializeSecurityContext returned SEC_E_OK, the 
// handshake completed successfully.


    if(scRet == SEC_E_OK)
    {
//--------------------------------------------------------------------
// If the "extra" buffer contains data, this is encrypted application
// protocol layer information. It needs to be saved. The
// application layer will later decrypt it with DecryptMessage.

        if(InBuffers[1].BufferType == SECBUFFER_EXTRA)
        {
            MoveMemory(
                rgbIoBuffer,
                (LPBYTE)(rgbIoBuffer + (cbIoBuffer - 
                           InBuffers[1].cbBuffer)),
                InBuffers[1].cbBuffer);
            cbIoBuffer = InBuffers[1].cbBuffer;
        }
        else
        {
            cbIoBuffer = 0;            
        }
//--------------------------------------------------------------------
// The handshake is over.
        return TRUE;
    }

//--------------------------------------------------------------------
// Check for fatal error.

    if(FAILED(scRet))
    {
        printf("**** Error 0x%x returned by 
                 InitializeSecurityContext\n", scRet);
        break;
    }

//--------------------------------------------------------------------
// If InitializeSecurityContext returned SEC_I_INCOMPLETE_CREDENTIALS,
// the server just requested client authentication. 

    if(scRet == SEC_I_INCOMPLETE_CREDENTIALS)
    {
//--------------------------------------------------------------------
// The user could be prompted to select a client certificate and 
// obtain a new credential handle at this pont. 

        fDoRead = FALSE;
        scRet   = SEC_I_CONTINUE_NEEDED;
        continue;
    }

//--------------------------------------------------------------------
// Copy any leftover data from the "extra" buffer, and go around
// again.

    if ( InBuffers[1].BufferType == SECBUFFER_EXTRA )
    {
        MoveMemory(IoBuffer,
                   IoBuffer + (cbIoBuffer - InBuffers[1].cbBuffer),
                   InBuffers[1].cbBuffer);

        cbIoBuffer = InBuffers[1].cbBuffer;
    }
    else
    {
        cbIoBuffer = 0;
    }
}