GSSAPI との SSPI/Kerberos 相互運用性

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

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

Windows-Compatible名

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

gss_get_micおよびgss_verify_mic関数を使用するように GSSAPI ベースのプロトコル指定されている場合、正しい SSPI 関数は MakeSignature および VerifySignature になります。 makeSignatureVerifySignature は、conf_flagが 0 に設定されている場合、または GSS_Unwrap で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.