Platform SDK: Logon Authentication

SSPI/Kerberos Interoperability with GSSAPI

Care must be taken when using the Kerberos SSP if interoperability with GSSAPI is a requirement. The following coding conventions allow interoperability with GSSAPI-based applications:

Sample code can be found in the Platform SDK under Samples\Winbase\Security\Win200\Gss. In addition, the equivalent Unix sample is distributed in the MIT and Heimdal Kerberos distributions, gss client and server.

Windows 2000 Compatible Names

GSSAPI functions use a name format known as gss_nt_service_name as specified in the RFC. Note in the GSSAPI name, 'nt' does not stand for 'NT.' sample@host.dom.com is an example of a name that can be used in a GSSAPI based application. Windows 2000 does not recognize the gss_nt_service_name format, and the full service principal name, for example sample/host.dom.com@REALM, must be used.

Authentication

Authentication is usually handled when a connection is first set up between a client and server. In this example, the client is using SSPI and the server is using GSSAPI.

In the SSPI client:

  1. Get outbound credentials using AcquireCredentialsHandle.
  2. Create service name with gss_import_name() and get inbound credentials using gss_aquire_cred.
  3. Get authentication token to send to server using InitializeSecurityContext.
  4. Send token to server.

In the GSSAPI server:

  1. Parse message from client to extract security token. Use gss_accept_sec_context passing token as argument.
  2. Parse message from server to extract security token. Pass to InitializeSecurityContext.
  3. Send response token to client.

    gss_accept_sec_context can return a token to send back to the client.

  4. If continue needed, send token to server; otherwise connection is completed
  5. If continue needed, wait for next token from client; otherwise connection is completed

Message Integrity and Privacy

Most GSSAPI-based applications use GSS_Wrap to sign a message before sending it. Conversely, GSS_Unwrap verifies the signature. GSS_Wrap is a new part of the API (v2) and is now widely used and specified in Internet standards that describe using the GSSAPI for adding security to protocols. Earlier, the GSS SignMessage and SealMessage functions were used for message integrity and privacy. GSS_Wrap and GSS_Unwrap are used for both integrity and privacy with the use of privacy controlled by the value of the "conf_flag" argument.

If a GSSAPI-based protocol is specified to use gss_get_mic and gss_verify_mic, the correct SSPI functions would be MakeSignature and VerifySignature. Be aware that MakeSignature and VerifySignature will not interoperate with gss_wrap with conf_flag set to zero or with gss_unwrap. The same is true for mixing EncryptMessage set for signature only and gss_verify_mic.

Note  Do not use the MakeSignature or VerifySignature functions when GSS_Wrap and GSS_Unwrap are called for.

The SSPI equivalent to GSS_Wrap is EncryptMessage for both integrity and privacy.

The following code sample shows using EncryptMessage to sign data that will be verified by GSS_Unwrap.

In the SSPI client:

// Need 3 descriptors - 2 for the SSP and one to hold the application data 
in_buf_desc.cBuffers = 3;
in_buf_desc.pBuffers = wrap_bufs;
in_buf_desc.ulVersion = SECBUFFER_VERSION;
wrap_bufs[0].cbBuffer = sizes.cbSecurityTrailer;
wrap_bufs[0].BufferType = SECBUFFER_TOKEN;
wrap_bufs[0].pvBuffer = malloc(sizes.cbSecurityTrailer);
// This buffer holds the application data
wrap_bufs[1].BufferType = SECBUFFER_DATA;
wrap_bufs[1].cbBuffer = in_buf.cbBuffer;
wrap_bufs[1].pvBuffer = malloc(wrap_bufs[1].cbBuffer);
memcpy(wrap_bufs[1].pvBuffer, in_buf.pvBuffer, in_buf.cbBuffer);
wrap_bufs[2].BufferType = SECBUFFER_PADDING;
wrap_bufs[2].cbBuffer = sizes.cbBlockSize;
wrap_bufs[2].pvBuffer = malloc(wrap_bufs[2].cbBuffer);
maj_stat = EncryptMessage(&context,
SignOnly ? KERB_WRAP_NO_ENCRYPT : 0,
&in_buf_desc, 0);

// Send message to server

In the GSSAPI server:

// Received message is in recv_buf 
maj_stat = gss_unwrap(&min_stat, context, &recv_buf, &msg_buf, &conf_state, (gss_qop_t *) NULL);
(void) gss_release_buffer(&min_stat, &recv_buf);
// Original message is in msg_buf

The SSPI equivalent to GSS_Unwrap is DecryptMessage. Here is a code sample that shows how to use DecryptMessage to decrypt data that was encrypted by GSS_Wrap.

In the GSSAPI server:

// Seal the message
send_buf.value = msg;
send_buf.length = msglen;
// If encrypt_flag = 1, privacy; encrypt_flag = 0, integrity
maj_stat = gss_wrap(&min_stat, context, encrypt_flag, GSS_C_QOP_DEFAULT,
&send_buf, &state, &msg_buf); 
// The message to send is in msg_buf

In the SSPI client:

wrap_buf_desc.cBuffers = 2;
wrap_buf_desc.pBuffers = wrap_bufs;
wrap_buf_desc.ulVersion = SECBUFFER_VERSION; 
// This buf is for SSPI
wrap_bufs[0].BufferType = SECBUFFER_STREAM;
wrap_bufs[0].pvBuffer = xmit_buf.pvBuffer;
wrap_bufs[0].cbBuffer = xmit_buf.cbBuffer;
// This buf holds the application data
wrap_bufs[1].BufferType = SECBUFFER_DATA;
wrap_bufs[1].cbBuffer = 0;
wrap_bufs[1].pvBuffer = NULL;
maj_stat = DecryptMessage(
&context,
&wrap_buf_desc,
0, // no sequence number
&qop
);
// This is where the data is
msg_buf = wrap_bufs[1];
// Check QOP of received message.
// if qop is KERB_WRAP_NO_ENCRYPT, the message is signed only, 
// otherwise it is encrypted.