共用方式為


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 用戶端中設定驗證

  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 將安全性新增至通訊協定。 先前,GSS SignMessage 和 SealMessage 函式用於訊息完整性隱私權。 GSS_Wrap和GSS_Unwrap用於完整性和隱私權,並使用由 「conf_flag」 自變數值控制的隱私權。

如果指定 GSSAPI 型通訊協定來使用gss_get_mic和gss_verify_mic函式,則正確的 SSPI 函式會是 MakeSignatureVerifySignature。 請注意,當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.