SSPI/Kerberos 与 GSSAPI 的互操作性

如果需要与 GSSAPI 的互操作性,在使用 Kerberos安全支持提供程序 (SSP) 时必须小心。 以下代码约定允许与基于 GSSAPI 的应用程序进行互操作性:

可以在 Samples\Security\SSPI\GSS 下的平台软件开发工具包 (SDK) 中找到示例代码。 此外,等效的 UNIX 示例在 MIT 和 Heimdal Kerberos 分发版、GSS 客户端和服务器中分发。

Windows-Compatible名称

GSSAPI 函数使用 RFC 中指定的名为 gss_nt_service_name 的名称格式。 例如, sample@host.dom.com 是可在基于 GSSAPI 的应用程序中使用的名称。 Windows 操作系统无法识别gss_nt_service_name格式,必须使用完整的 服务主体名称,例如 sample/host.dom.com@REALM。

身份验证

通常在客户端和服务器之间首次设置连接时处理身份验证。 在此示例中,客户端使用 安全支持提供程序接口 (SSPI) ,服务器使用 GSSAPI。

在 SSPI 客户端中设置身份验证

  1. 使用 AcquireCredentialsHandle 获取出站凭据
  2. 使用 gss_import_name () 创建服务名称,并使用 gss_acquire_cred 获取入站凭据。
  3. 使用 InitializeSecurityContext (Kerberos) 获取要发送到服务器的身份验证令牌。
  4. 将令牌发送到服务器。

在 GSSAPI 服务器中设置身份验证

  1. 分析来自客户端的消息以提取安全令牌。 使用 gss_accept_sec_context 函数,将令牌作为参数传递。

  2. 分析来自服务器的消息以提取安全令牌。 将此安全令牌传递给 InitializeSecurityContext (Kerberos)

  3. 将响应令牌发送到客户端。

    gss_accept_sec_context 函数可以返回可以发送回客户端的令牌。

  4. 如果需要继续,请向服务器发送响应令牌;否则,身份验证设置已完成。

  5. 如果需要继续,请等待来自客户端的下一个令牌;否则,身份验证设置已完成。

消息完整性和隐私

大多数基于 GSSAPI 的应用程序在发送消息之前使用 GSS_Wrap 函数对消息进行签名。 相反, GSS_Unwrap 函数验证签名。 GSS_Wrap 在 API 版本 2.0 中可用,现在在描述使用 GSSAPI 为协议添加安全性的 Internet 标准中广泛使用和指定。 此前,GSS SignMessageSealMessage 函数用于消息 完整性隐私GSS_WrapGSS_Unwrap 用于完整性和隐私,使用由“conf_flag”参数的值控制的隐私。

如果指定基于 GSSAPI 的协议以使用 gss_get_micgss_verify_mic 函数,则正确的 SSPI 函数将是 MakeSignatureVerifySignature。 请注意,当conf_flag设置为零或与GSS_Unwrap时,MakeSignatureVerifySignature 不会与GSS_Wrap互操作。 将 EncryptMessage (Kerberos) 设置为“仅签名”和“ gss_verify_mic”时也是如此。

注意

调用 GSS_WrapGSS_Unwrap 时,请勿使用 MakeSignatureVerifySignature 函数。

 

GSS_Wrap 等效的 SSPI 是 EncryptMessage (Kerberos) ,以确保完整性和隐私性。

以下示例演示如何使用 EncryptMessage (Kerberos) 对将由 GSS_Unwrap 验证的数据进行签名。

在 SSPI 客户端中:

// Need three descriptors, two 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 a message to the server.

在 GSSAPI 服务器中:

// 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.

GSS_Unwrap 等效的 SSPI 是 DecryptMessage (Kerberos) 。 以下示例演示如何使用 DecryptMessage (Kerberos) 解密 GSS_Wrap加密的数据。

在 GSSAPI 服务器中:

// 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.

在 SSPI 客户端中:

wrap_buf_desc.cBuffers = 2;
wrap_buf_desc.pBuffers = wrap_bufs;
wrap_buf_desc.ulVersion = SECBUFFER_VERSION; 

// This buffer is for SSPI.
wrap_bufs[0].BufferType = SECBUFFER_STREAM;
wrap_bufs[0].pvBuffer = xmit_buf.pvBuffer;
wrap_bufs[0].cbBuffer = xmit_buf.cbBuffer;

// This buffer 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.