Server Authentication

The code in this topic describes the client and server interactions to create a security context.

The example begins after the client makes its initial call to the InitializeSecurityContext function and sends the output to the server. The example assumes that the security buffer produced by the client's call to InitializeSecurityContext is in InputSecurityBuffer, and the length of that buffer is in InputSecurityBufferSize.

The example begins with the server's first call to the AcceptSecurityContext function.

CtxtHandle ServerContext;
TimeStamp Expiration;
SecBufferDesc InputBufferDescriptor;
SecBuffer InputSecurityToken;
SecBufferDesc OutputBufferDescriptor;
SecBuffer OutputSecurityToken;
ULONG ContextRequirements;
ULONG ContextAttributes;

//
// Build the input buffer descriptor.
//

InputBufferDescriptor.cBuffers = 1
InputBufferDescriptor.pBuffers = &InputSecurityToken;
InputBufferDescriptor.ulVersion = SECBUFFER_VERSION;

InputSecurityToken.BufferType = SECBUFFER_TOKEN;
InputSecurityToken.cbBuffer = InputSecurityBufferSize;
InputSecurityToken.pvBuffer = InputSecurityBuffer;

//
// Build the output buffer descriptor. We need to allocate a buffer
// to hold this buffer.
//

OutputBufferDescriptor.cBuffers = 1
OutputBufferDescriptor.pBuffers = &OutputSecurityToken;
OutputBufferDescriptor.ulVersion = SECBUFFER_VERSION;

OutputSecurityToken.BufferType = SECBUFFER_TOKEN;
OutputSecurityToken.cbBuffer = PackageInfo->cbMaxToken;
OutputSecurityToken.pvBuffer = LocalAlloc(0, PackageInfo->cbMaxToken);

//
// Check for memory allocation failure here.
//

//
// We can pass zero for the context requirements because the buffer 
// from the client will negotiate those requirements.
//

SecStatus = AcceptSecurityContext(
      &ServerCredential,
      NULL,                     // no context handle yet
      &InputBufferDescriptor,
      0,                        // no context requirements
      SECURITY_NATIVE_DREP,
      &ServerContext,           // receives new context handle
      &OutputBufferDescriptor,  // receives output security token
      &ContextAttributes,       // receives context attributes
      &Expiration               // receives context expiration time
      );
 

If this AcceptSecurityContext call is successful, it returns SEC_I_CONTINUE_NEEDED, and the server transmits the output security buffer and length back to the client. If it fails, it returns an error code.

The client makes a second call to the InitializeSecurityContext function. The parameters are similar to the first call. The example assumes that the security buffer returned from the server is in InputSecurityBuffer, and the length of that buffer is in InputSecurityBufferSize.

TimeStamp Expiration;
SecBufferDesc OutputBufferDescriptor;
SecBuffer OutputSecurityToken;
SecBufferDesc InputBufferDescriptor;
SecBuffer InputSecurityToken;
ULONG ContextAttributes;

//
// Build the input buffer descriptor.
//

InputBufferDescriptor.cBuffers = 1
InputBufferDescriptor.pBuffers = &InputSecurityToken;
InputBufferDescriptor.ulVersion = SECBUFFER_VERSION;

InputSecurityToken.BufferType = SECBUFFER_TOKEN;
InputSecurityToken.cbBuffer = InputSecurityBufferSize;
InputSecurityToken.pvBuffer = InputSecurityBuffer;

//
// Build the output buffer descriptor.
//

OutputBufferDescriptor.cBuffers = 1
OutputBufferDescriptor.pBuffers = &OutputSecurityToken;
OutputBufferDescriptor.ulVersion = SECBUFFER_VERSION;

OutputSecurityToken.BufferType = SECBUFFER_TOKEN;
OutputSecurityToken.cbBuffer = PackageInfo->cbMaxToken;
OutputSecurityToken.pvBuffer = 
        LocalAlloc(0, OutputSecurityToken.cbBuffer);

//
// Check for memory allocation failure here.
//


//
// We can ignore the pszTargetName and fContextReq parameters on this
// call, because we passed them on the first call. This time,
// instead of passing NULL for phContext, we pass the context 
// handle received on the first call. 
//

SecStatus = InitializeSecurityContext(
      &ClientCredential
      &ClientContext,
      NULL,                     // no target name this time
      0,                        // no context requirements
      0,                        // reserved parameter
      SECURITY_NATIVE_DREP,     // target data representation
      &InputBufferDescriptor,   // input buffer
      0,                        // reserved parameter
      &ClientContext,           // same as the old context
      &ContextAttributes,       // receives context attributes
      &OutputBufferDescriptor,  // receives output security token
      &Expiration               // receives context expiration time
      );
 

If this InitializeSecurityContext call is successful, it returns SEC_E_OK, and the client transmits the output security buffer and buffer length to the server, as it did after the first call to InitializeSecurityContext. If it fails, it returns an error code.

The client has now finished setting up the security context. The client can begin using the security context in calls to the MakeSignature and VerifySignature functions to make and verify message signatures, even though the server has not yet finished authenticating the client.

The server makes the final call to AcceptSecurityContext. The input buffer and buffer size are assumed to be in InputSecurityBuffer and InputSecurityBufferSize. On this call, there is no output message, so we pass NULL for the pOutput parameter.

TimeStamp Expiration;
SecBufferDesc InputBufferDescriptor;
SecBuffer InputSecurityToken;
ULONG ContextAttributes;

//
// Build the input buffer descriptor.
//

InputBufferDescriptor.cBuffers = 1
InputBufferDescriptor.pBuffers = &InputSecurityToken;
InputBufferDescriptor.ulVersion = SECBUFFER_VERSION;

InputSecurityToken.BufferType = SECBUFFER_TOKEN;
InputSecurityToken.cbBuffer = InputSecurityBufferSize;
InputSecurityToken.pvBuffer = InputSecurityBuffer;

//
// This time, instead of passing NULL for phContext, we pass the 
// context handle we received on the first call. 
//

SecStatus = AcceptSecurityContext(
      &ServerCredential
      &ServerContext,
      &InputBufferDescriptor,  // input buffer
      0,                       // no context requirements.
      SECURITY_NATIVE_DREP,    // target data representation
      &ServerContext,          // same as the old context
      &ContextAttributes,      // receives context attributes
      NULL,                    // no output security token 
      &Expiration              // receives context expiration time
      );
 

This AcceptSecurityContext call returns SEC_E_OK if successful, or an error code if it fails. If this succeeds, the client was successfully authenticated. The server can now call the ImpersonateSecurityContext function to impersonate the caller, the QueryContextAttributes function to obtain the caller's identity, as well as the MakeSignature and VerifySignature functions to make and verify message signatures.