GSSAPI との SSPI/Kerberos 相互運用性

GSSAPI との相互運用性要件である場合は、Kerberos セキュリティ サポート プロバイダー (SSP) を使用する際に注意が必要です。 次のコード規則を使用すると、GSSAPI ベースのアプリケーションとの相互運用性を実現できます。

サンプル コードは、プラットフォーム ソフトウェア開発キット (SDK) の Samples\Security\SSPI\GSS にあります。 さらに、同等の UNIX サンプルは、MIT および Heimdal Kerberos ディストリビューション、GSS クライアント、およびサーバーで配布されます。

Windows と互換性のある名前

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 はバージョン 2.0 の API で使用でき、現在では広く使用されており、プロトコルにセキュリティを追加するための GSSAPI の使用について説明するインターネット標準に明記されています。 以前は、GSS SignMessage および SealMessage 関数が、メッセージの整合性プライバシーのために使用されていました。 GSS_WrapGSS_Unwrap は、整合性とプライバシーの両方に使用され、プライバシーの使用は "conf_flag" 引数の値によって制御されます。

gss_get_mic 関数と gss_verify_mic 関数を使用するように GSSAPI ベースのプロトコルが指定されている場合、正しい SSPI 関数は MakeSignatureVerifySignature になります。 MakeSignatureVerifySignatureGSS_Wrap (conf_flagが 0 に設定されている場合)、または GSS_Unwrap と相互運用できないことに注意してください。 署名のみに設定された EncryptMessage (Kerberos)gss_verify_mic を混在する場合にも、同じことが当てはまります。

Note

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.