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 客户端中设置身份验证
- 使用 AcquireCredentialsHandle 获取出站凭据。
- 使用 gss_import_name () 创建服务名称,并使用 gss_acquire_cred 获取入站凭据。
- 使用 InitializeSecurityContext (Kerberos) 获取要发送到服务器的身份验证令牌。
- 将令牌发送到服务器。
在 GSSAPI 服务器中设置身份验证
分析来自客户端的消息以提取安全令牌。 使用 gss_accept_sec_context 函数,将令牌作为参数传递。
分析来自服务器的消息以提取安全令牌。 将此安全令牌传递给 InitializeSecurityContext (Kerberos) 。
将响应令牌发送到客户端。
gss_accept_sec_context 函数可以返回可以发送回客户端的令牌。
如果需要继续,请向服务器发送响应令牌;否则,身份验证设置已完成。
如果需要继续,请等待来自客户端的下一个令牌;否则,身份验证设置已完成。
消息完整性和隐私
大多数基于 GSSAPI 的应用程序在发送消息之前使用 GSS_Wrap 函数对消息进行签名。 相反, GSS_Unwrap 函数验证签名。 GSS_Wrap 在 API 版本 2.0 中可用,现在在描述使用 GSSAPI 为协议添加安全性的 Internet 标准中广泛使用和指定。 此前,GSS SignMessage 和 SealMessage 函数用于消息 完整性 和 隐私。 GSS_Wrap 和 GSS_Unwrap 用于完整性和隐私,使用由“conf_flag”参数的值控制的隐私。
如果指定基于 GSSAPI 的协议以使用 gss_get_mic 和 gss_verify_mic 函数,则正确的 SSPI 函数将是 MakeSignature 和 VerifySignature。 请注意,当conf_flag设置为零或与GSS_Unwrap时,MakeSignature 和 VerifySignature 不会与GSS_Wrap互操作。 将 EncryptMessage (Kerberos) 设置为“仅签名”和“ gss_verify_mic”时也是如此。
注意
调用 GSS_Wrap 和 GSS_Unwrap 时,请勿使用 MakeSignature 或 VerifySignature 函数。
与 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.
反馈
https://aka.ms/ContentUserFeedback。
即将发布:在整个 2024 年,我们将逐步淘汰作为内容反馈机制的“GitHub 问题”,并将其取代为新的反馈系统。 有关详细信息,请参阅:提交和查看相关反馈