SSPI/Kerberos 與 GSSAPI 互操作性
如果使用 Kerberos 安全性支援提供者 (SSP),就必須小心,如果與 GSSAPI 的互操作性是必要條件。 下列程式代碼慣例允許與 GSSAPI 型應用程式的互操作性:
您可以在 Samples\Security\SSPI\GSS 之下的平台軟體開發工具包 (SDK) 中找到範例程式代碼。 此外,相等的 UNIX 範例會分散在 MIT 和 Heimdal Kerberos 散發套件、GSS 用戶端和伺服器中。
Windows 相容名稱
GSSAPI 函式會使用名為 gss_nt_service_name 的名稱格式,如 RFC 中所指定。 例如, sample@host.dom.com 是可在 GSSAPI 型應用程式中使用的名稱。 Windows 作業系統無法辨識gss_nt_service_name格式,而且 必須使用範例/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 將安全性新增至通訊協定。 先前,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.