GSS-API のプログラミング

コンテキストの確立

前述のとおり、GSS-API がセキュリティの提供において行う最も重要な 2 つの仕事は、セキュリティコンテキストを作成することと、データを保護することです。必要な資格を取得した後、アプリケーションはセキュリティコンテキストを確立します。このためには、一方のアプリケーション (通常はクライアント) がコンテキストを起動して、もう一方のアプリケーション (通常はサーバー) がそのコンテキストを受け入れます。ピア間で複数のコンテキストが存在してもかまいません。

通信中のアプリケーションは、認証トークンを交換することによって、結合セキュリティコンテキストを確立します。セキュリティコンテキストは、2 つのアプリケーション間で共有される情報が入っている一対の GSS-API データ構造体です。この情報は、各アプリケーションの (セキュリティにおける) 状態を記述します。セキュリティコンテキストはデータの保護のために必要です。

コンテキストの起動 (クライアント)

アプリケーションとリモートピア間でのセキュリティコンテキストの起動は、gss_init_sec_context() 関数で行います。成功した場合、gss_init_sec_context() 関数は確立中のコンテキストのコンテキストハンドルと、受け入れ側に送信するコンテキストレベルトークンを戻します。しかし、gss_init_sec_context() を呼び出す前に、クライアントは次のことを行う必要があります。

  1. 必要であれば、gss_acquire_cred() で資格を獲得します。しかし、通常、クライアントはログイン時に資格を受け取っているため、その場合、この手順は飛ばすことができます。

  2. gss_import_name() で、サーバー名を GSS-API 内部形式にインポートします。名前と gss_import_name() についての詳細は、名前を参照してください。

gss_init_sec_context() を呼び出すとき、通常、クライアントは次の引数値を渡します。

アプリケーションは必ずしもこのようなデフォルト値を使用する必要はありません。さらに、クライアントは req_flags 引数を使用して、他のセキュリティパラメータに対する要件を指定することもあります。gss_init_sec_context() 引数についての詳細は、以降の節で説明します。

コンテキストを確立するために、コンテキスト受け入れ側はいくつかの「ハンドシェーク」を要求できます。つまり、コンテキストが完全に確立されたと考えられるまでに、複数のコンテキスト情報を送信するように起動側に要求できます。したがって、移植性のため、コンテキストの起動は常に、コンテキストが完全に確立されたかどうかを検査するループの一部として行われる必要があります。

コンテキストが完全に確立されていない場合、gss_init_sec_context() はメジャー状態コードとして GSS_C_CONTINUE_NEEDED を戻します。したがって、ループは gss_init_sec_context() の戻り値を使用して、起動ループを継続するかどうかをテストする必要があります。

クライアントはコンテキスト情報をサーバーに、gss_init_sec_context() から戻された出力トークンの形式で渡します。その後、クライアントはこの情報をサーバーから入力トークンとして受け取ります。すると、後続の gss_init_sec_context() の呼び出しに引数として渡すことができます。受け取った入力トークンの長さが 0 の場合、サーバーはこれ以上出力トークンを要求していないことが分かります。

したがって、gss_init_sec_context() の戻り状態を検査することに加えて、ループは入力トークンの長さを検査して、さらにトークンをサーバーに送信するのかどうかを判断する必要があります。ループが始まる前には、入力トークンを GSS_C_NO_BUFFER に設定するか、構造体の長さフィールドを 0 に設定することによって、入力トークンの長さを 0 に初期化する必要があります。

次に、このようなループの例を示します。かなり一般化されています。


context = GSS_C_NO_CONTEXT を入れる
input token = GSS_C_NO_BUFFER を入れる

do {

     gss_init_sec_context(credential, context, name, input_token, 
          output_token, other args...)

     if (受け入れ側に送信する output_token がある時)

          受け入れ側に output_token を送信
          output_token を解放する

     if (context が完全でない時)

          受け入れ側から input_token を受け取る

     if (GSS-API エラーがある時)
          context を削除する

} while (context が完全になるまで)

当然、実際のループはより複雑になります。たとえば、より多くのエラー検査が必要になるなどです。このようなコンテキスト起動ループの実際の例については、コンテキストの確立(プログラムリストは client_establish_context()) を参照してください。さらに、gss_init_sec_context(3GSS) のマニュアルページにも、上記例ほど一般化されていない例があります。

繰り返しますが、GSS-API 自身はトークンを送受信しません。トークンの送受信はアプリケーションが処理する必要があります。トークン転送関数の例については、send_token()recv_token()を参照してください。

次に、gss_init_sec_context() の形式を示します。詳細は、gss_init_sec_context(3GSS) のマニュアルページを参照してください。


例 1–6 gss_init_sec_context()


     OM_uint32 gss_init_sec_context (
       OM_uint32                    *minor_status,
       const gss_cred_id_t          initiator_cred_handle,
       gss_ctx_id_t                 *context_handle,
       const gss_name_t             target_name,
       const gss_OID                mech_type,
       OM_uint32                    req_flags,
       OM_uint32                    time_req,
       const gss_channel_bindings_t input_chan_bindings,
       const gss_buffer_t           input_token
       gss_OID                      *actual_mech_type,
       gss_buffer_t                 output_token,
       OM_uint32                    *ret_flags,
       OM_uint32                    *time_rec )

minor_status

実際の機構から戻される状態コード。

initiator_cred_handle

アプリケーションの資格ハンドル。デフォルトの資格を使用することを示すには、GSS_C_NO_CREDENTIAL に初期化する必要があります。

context_handle

戻すべきコンテキストハンドル。ループが始まる前には、GSS_C_NO_CONTEXT に設定する必要があります。

target_name

接続先のプリンシパルの名前。たとえば、「nfs@machinename」などです。

mech_type

使用されるセキュリティ機構。GSS-API が提供するデフォルトを取得するには、GSS_C_NO_OID に設定します。

req_flags

このコンテキストで要求される追加のサービスまたはパラメータを示すフラグ。req_flags フラグは次のようにビット論理和をとって、希望のビットマスク値を作成する必要があります。


GSS_C_MUTUAL_FLAG | GSS_C_DELEG_FLAG

GSS_C_DELEG_FLAG

起動側の資格を委託できるように要求します。委託を参照してください。

GSS_C_MUTUAL_FLAG

相互認証を要求します。相互認証を参照してください。

GSS_C_REPLAY_FLAG

繰り返しメッセージを検出するように要求します。誤順序の検出とリプレイの検出を参照してください。

GSS_C_SEQUENCE_FLAG

誤順序メッセージを検出するように要求します。誤順序の検出とリプレイの検出を参照してください。

GSS_C_CONF_FLAG

転送されるメッセージに機密性サービスを適用するように、つまり、メッセージを暗号化するように要求します。機密性が許可されない場合、データ起点認証と (GSS_C_INTEG_FLAG が偽でなければ) 整合性サービスだけを適用できます。

GSS_C_INTEG_FLAG

メッセージに整合性サービスを適用するように、つまり、メッセージに MIC を付けて有効性を保証するように要求します。

GSS_C_ANON_FLAG

起動側が匿名のままであるように要求します。匿名認証を参照してください。

time_req

コンテキストが有効であるべき時間 (秒)。デフォルトを要求するには、0 に設定します。

input_chan_bindings

セキュリティコンテキストに接続された特定のピアツーピアのチャネル識別情報。チャネルバインディングについての詳細は、チャネルバインディングを参照してください。チャネルバインディングを使用しない場合は、GSS_C_NO_CHANNEL_BINDINGS に設定します。

input_token

コンテキスト受け入れ側から受信したトークン (もしあれば)。関数が呼び出される前に、GSS_C_NO_BUFFER に初期化する (あるいは、長さフィールドを 0 に設定する) 必要があります。

actual_mech_type

コンテキストで実際に使用される機構。どの機構が使用されるかを知る必要がない場合は、NULL に設定します。

output_token

受け入れ側に送信すべきトークン。

ret_flags

このコンテキストで要求された、追加のサービスまたはパラメータを示すフラグ。ret_flags フラグは次のようにビット論理積をとって、戻されたビットマスク値をテストする必要があります。


if (ret_flags & GSS_C_CONF_FLAG)
     confidentiality = TRUE;

GSS_C_DELEG_FLAG

真の場合、起動側の資格が委託できることを示します。委託を参照してください。

GSS_C_MUTUAL_FLAG

真の場合、相互認証が使用できることを示します。相互認証を参照してください。

GSS_C_REPLAY_FLAG

真の場合、繰り返しメッセージの検出が有効であることを示します。誤順序の検出とリプレイの検出を参照してください。

GSS_C_SEQUENCE_FLAG

真の場合、誤順序メッセージの検出が有効であることを示します。誤順序の検出とリプレイの検出を参照してください。

GSS_C_CONF_FLAG

真の場合、転送されるメッセージに機密性サービスを適用できます。つまり、メッセージを暗号化できます。機密性が許可されない場合、データ起点認証と (GSS_C_INTEG_FLAG が偽でなければ) 整合性サービスだけを適用できます。

GSS_C_INTEG_FLAG

真の場合、メッセージに整合性サービスを適用できます。つまり、メッセージに MIC (Message Integrity Code) を付けて有効性を保証できます。

GSS_C_ANON_FLAG

真の場合、コンテキスト起動側が匿名のままであることを示します。匿名認証を参照してください。

GSS_C_PROT_READY_FLAG

コンテキストの確立に時間がかかり、完了するまで、クライアントが待機する場合もあります。コンテキストが完全に確立されていない場合でも、gss_init_sec_context() は、コンテキストが完全に確立された後にどの保護サービスが使用できるかを (もしあれば) 示すことができます。したがって、アプリケーションはデータをバッファに格納しておいて、コンテキストが完全に確立された後で、バッファに格納しておいたデータを送信できます。

ret_flagsGSS_C_PROT_READY_FLAG を示す場合、コンテキストが完全に確立されていない場合でも (つまり、gss_init_sec_context()GSS_S_CONTINUE_NEEDED を戻す場合でも)、GSS_C_CONF_FLAGGSS_C_INTEG_FLAG が示す保護サービスを使用できます。すると、アプリケーションは希望の保護サービスに適切なラップ関数 (gss_wrap() または gss_get_mic()) を呼び出し、さらに、コンテキストが完全に確立されたときに転送する出力をバッファに格納できます。

GSS_C_PROT_READY_FLAG が偽の場合、アプリケーションはデータ保護を仮定できず、コンテキストの確立が完了するまで (つまり、gss_init_sec_context()GSS_S_COMPLETE を戻すまで) 待機する必要があります。


注 –

GSS-API の以前のバージョンは GSS_C_PROT_READY_FLAG 引数をサポートしていません。したがって、移植性を最大限にしたい開発者は、コンテキストの確立が完了した後で GSS_C_CONF_FLAGGSS_C_INTEG_FLAG フラグを調べて、どのメッセージ毎サービスを使用できるかを判断する必要があります。


GSS_C_TRANS_FLAG

このコンテキストがエクスポートできるかどうかを示します。コンテキストのインポートとエクスポートについての詳細は、コンテキストのエクスポートとインポートを参照してください。

time_rec

資格が有効である時間 (秒)。時間が重要でない場合は、NULL に設定します。

一般に、コンテキストが完全に確立されていない時に戻されるパラメータ値は、コンテキストが完了する時に入力されるはずの値です。詳細は、gss_init_sec_context() のマニュアルページを参照してください。

正常に終了した場合、gss_init_sec_context()GSS_S_COMPLETE を戻します。コンテキスト確立トークンがピアとなるアプリケーションから要求された場合、gss_init_sec_context()GSS_S_CONTINUE_NEEDED を戻します。エラーが発生した場合、gss_init_sec_context() はエラーコードを戻します。エラーコードについては、gss_init_sec_context(3GSS) のマニュアルページを参照してください。

コンテキストの起動が失敗した場合、クライアントはサーバーから切断する必要があります。

コンテキストの受け入れ (サーバー)

コンテキストの確立におけるもう一つの仕事は、コンテキストの受け入れです。コンテキストの受け入れは gss_accept_sec_context() 関数で行います。通常、クライアントが (gss_init_sec_context() で) コンテキストを起動し、サーバーがそのコンテキストを受け入れます。

gss_accept_sec_context() は、起動側から送信された入力トークンを主な入力として使用します。gss_accept_sec_context() は、コンテキストハンドルと起動側に戻すべき出力トークンを戻します。しかし、gss_accept_sec_context() を呼び出す前に、サーバーはクライアントから要求されたサービスの資格を獲得しておく必要があります。サーバーはこのような資格を gss_acquire_cred() 関数で獲得します。あるいは、サーバーは資格を明示的に獲得するのではなく、gss_accept_sec_context() を呼び出すときにデフォルトの資格を指定する (GSS_C_NO_CREDENTIAL で示す) ことも可能です。

gss_accept_sec_context() を呼び出すとき、サーバーは次の引数値を渡します。

gss_accept_sec_context() 引数についての詳細は、以降の節で説明します。

セキュリティコンテキストを確立するためには、いくつかの「ハンドシェーク」が必要です。つまり、コンテキストが完全に確立されるまでに、起動側と受け入れ側は複数のコンテキスト情報を送信する必要があることがあります。したがって、移植性のため、コンテキストの受け入れは常に、コンテキストが完全に確立されたかどうかを検査するループの一部として行われる必要があります。コンテキストが完全に確立されていない場合、gss_accept_sec_context() はメジャー状態コードとして GSS_C_CONTINUE_NEEDED を戻します。したがって、ループは gss_accept_sec_context() の戻り値を使用して、受け入れループを継続するかどうかをテストする必要があります。

コンテキスト受け入れ側はコンテキスト情報をコンテキスト起動側に、gss_accept_sec_context() から戻された出力トークンの形式で渡します。その後、受け入れ側は以降の情報を起動側から入力トークンとして受け取ります。すると、後続の gss_accept_sec_context() の呼び出しに引数として渡すことができます。起動側に送信するトークンがなくなったとき、gss_accept_sec_context() は、length の値が 0 の出力トークンを戻します。したがって、gss_accept_sec_context() の戻り状態を検査することに加えて、ループは出力トークンの length を検査して、さらにトークンを送信するのかどうかを判断する必要があります。ループが始まる前には、出力トークンを GSS_C_NO_BUFFER に設定するか、構造体の length フィールドを 0 に設定することによって、出力トークンの length を 0 に初期化する必要があります。

次に、このようなループの例を示します。かなり一般化されています。


context = GSS_C_NO_CONTEXT を入れる
input_token = GSS_C_NO_BUFFER を入れる

do {

     起動側から input_token を受け取る

     gss_accept_sec_context(context, cred_handle, input_token,
          output_token, other args...)

     if (起動側に送信する output_token がある時)

          起動側に output_token を送信
          output_token を解放する

     if (GSS-API エラーがある時)

          context を削除する

} while (context が完全になるまで)

当然、実際のループはより複雑になります。たとえば、より多くのエラー検査が必要になるなどです。このようなコンテキスト受け入れループの実際の例については、コンテキストの受け入れ(プログラムリストは server_establish_context()) を参照してください。さらに、gss_accept_sec_context(3GSS) のマニュアルページにも、上記例ほど一般化されていない例があります。

繰り返しますが、GSS-API 自身はトークンを送受信しません。トークンの送受信はアプリケーションが処理する必要があります。トークン転送関数の例については、send_token()recv_token()を参照してください。

次に、gss_accept_sec_context() の形式を示します。詳細は、gss_accept_sec_context(3GSS) のマニュアルページを参照してください。


例 1–7 gss_accept_sec_context()


     OM_uint32 gss_accept_sec_context (
       OM_uint32                    *minor_status,
       gss_ctx_id_t                 *context_handle,
       const gss_cred_id_t          acceptor_cred_handle,
       const gss_buffer_t           input_token_buffer,
       const gss_channel_bindings_t input_chan_bindings,
       const gss_name_t             *src_name,
       gss_OID                      *mech_type,
       gss_buffer_t                 output_token,
       OM_uint32                    *ret_flags,
       OM_uint32                    *time_req,
       gss_cred_id_t                *delegated_cred_handle)

minor_status

実際の機構から戻される状態コード。

context_handle

起動側に戻すべきコンテキストハンドル。ループが始まる前には、GSS_C_NO_CONTEXT に設定する必要があります。

acceptor_cred_handle

受け入れ側が (通常は、gss_acquire_cred() で) 獲得した資格のハンドル。GSS_C_NO_CREDENTIAL に初期化すると、デフォルトの資格を使用することを示すことができます。デフォルトの資格が定義されていない場合、GSS_C_NO_CRED を戻します。

(注: プリンシパル名として GSS_C_NO_NAME が渡された場合、gss_acquire_cred()gss_accept_sec_context() がデフォルトの資格として扱うような資格を生成します。)

input_token_buffer

コンテキスト起動側から受け取ったトークン。

input_chan_bindings

セキュリティコンテキストに接続された特定のピアツーピアチャネル識別情報。チャネルバインディングについての詳細は、チャネルバインディングを参照してください。チャネルバインディングを使用しない場合は、GSS_C_NO_CHANNEL_BINDINGS に設定します。

src_name

起動しているプリンシパルの名前。たとえば、nfs@machinename などです。プリンシパルの名前が重要でない場合は、NULL に設定します。

mech_type

使用されるセキュリティ機構。どの機構が使用されるかが重要でない場合は、NULL に設定します。

output_token

起動側に送信すべきトークン。関数が呼び出される前に、GSS_C_NO_BUFFER に初期化する (あるいは、長さフィールドを 0 に設定する) 必要があります。長さが 0 の場合、送信する必要のあるトークンはありません。

ret_flags

このコンテキストで要求された追加のサービスまたはパラメータを示すフラグ。ret_flags フラグは次のようにビット論理積をとって、戻されたビットマスク値をテストする必要があります。


if (ret_flags & GSS_C_CONF_FLAG)
     confidentiality = TRUE;

GSS_C_DELEG_FLAG

起動側の資格が delegated_cred_handle 引数経由で委託できることを示します。委託を参照してください。

GSS_C_MUTUAL_FLAG

相互認証が使用できることを示します。相互認証を参照してください。

GSS_C_REPLAY_FLAG

繰り返しメッセージの検出が有効であることを示します。誤順序の検出とリプレイの検出を参照してください。

GSS_C_SEQUENCE_FLAG

誤順序メッセージの検出が有効であることを示します。誤順序の検出とリプレイの検出を参照してください。

GSS_C_CONF_FLAG

真の場合、転送されるメッセージに機密性サービスを適用できます。つまり、メッセージを暗号化できます。機密性が許可されない場合、データ起点認証と (GSS_C_INTEG_FLAG が偽でなければ) 整合性サービスだけを適用できます。

GSS_C_INTEG_FLAG

真の場合、メッセージに整合性サービスを適用できます。つまり、メッセージに MIC (Message Integrity Code) を付けて有効性を保証できます。

GSS_C_ANON_FLAG

コンテキスト起動側が匿名のままであることを示します。匿名認証を参照してください。

GSS_C_PROT_READY_FLAG

コンテキストの確立に時間がかかる場合、コンテキストが完全に確立されていない場合でも、受け入れ側がコンテキスト関連のデータを処理できるように、クライアントは起動パスに十分な情報を送信できます。このような状況では、受け入れ側は情報がどのように保護されているかを (もしあれば) 知る必要があります。

GSS_C_PROT_READY_FLAG が真の場合、GSS_C_CONF_FLAGGSS_C_INTEG_FLAG が示す保護サービスを指定します。すると、受け入れ側は希望の保護サービスに適切なデータ受け入れ関数 (gss_unwrap() または gss_verify_mic()) を呼び出すことができます。

(さらに、コンテキスト起動側と同様に、受け入れ側はこれらのフラグを使用して、起動側に送信したいデータをバッファに格納しておいて、コンテキストが完全に確立された後で、バッファに格納しておいたデータを送信できます。)

GSS_C_PROT_READY_FLAG が偽の場合、受け入れ側はデータ保護を仮定できず、コンテキストの確立が完了するまで (つまり、gss_accept_sec_context()GSS_S_COMPLETE を戻すまで) 待機する必要があります。


注 –

GSS-API の以前のバージョンは GSS_C_PROT_READY_FLAG 引数をサポートしていません。したがって、移植性を最大限にしたい開発者は、コンテキストの確立が完了した後で GSS_C_CONF_FLAGGSS_C_INTEG_FLAG フラグを調べて、どのメッセージ毎サービスを使用できるかを判断する必要があります。


GSS_C_TRANS_FLAG

真の場合、このコンテキストがエクスポートできることを示します。コンテキストのインポートとエクスポートについての詳細は、コンテキストのエクスポートとインポートを参照してください。

time_rec

コンテキストが有効である時間 (秒)。時間が重要でない場合は、NULL に設定します。

delegated_cred_handle

コンテキスト起動側から受け取った資格 (つまり、クライアントの資格) の資格ハンドル。受け入れ側がプロクシとして動作するように起動側が要求した場合だけ、つまり、ret_flags 引数に GSS_C_DELEG_FLAG が含まれている場合だけ有効です。委託についての詳細は、委託を参照してください。

正常に終了した場合、gss_accept_sec_context()GSS_S_COMPLETE を戻します。コンテキストが完全に確立されていない場合、gss_accept_sec_context()GSS_S_CONTINUE_NEEDED を戻します。エラーが発生した場合、gss_accept_sec_context() はエラーコードを戻します。エラーコードについては、gss_accept_sec_context(3GSS) のマニュアルページを参照してください。

追加のコンテキストサービス

gss_init_sec_context() 関数 (コンテキストの起動 (クライアント)を参照) を使用すると、アプリケーションは基本のコンテキスト確立以外にも追加のデータ保護サービスも要求できます。このようなサービス (以降の節で説明) を要求するには、gss_init_sec_context()req_flags 引数を使用します。

すべての機構が追加の保護サービスを提供するわけではありません。したがって、特定のコンテキストで使用できる追加の保護サービスを調べるには、gss_init_sec_context()ret_flags 引数を使用します。同様に、コンテキスト受け入れ側も gss_accept_sec_context() 関数から戻された ret_flags の値を見て、どのサービスを使用できるかを判断します。以降の節では、追加のサービスについて説明します。

委託

可能であれば、コンテキスト起動側はコンテキスト受け入れ側がプロクシとして動作するように要求できます。この場合、受け入れ側は起動側の代わりに別のコンテキストを起動できます。このような委託の例としては、マシン A 上のユーザーがマシン B に rlogin し、次に、マシン B からマシン C に rlogin するなどです (図 1–8 を参照)。委託された資格がマシン B をマシン A として識別するか、あるいは、マシン A の代わりに動作しているマシン B と識別するかは、機構によって異なります。

図 1–8 資格の委託

Graphic

委託が許可されると、ret_flags に値 GSS_C_DELEG_FLAG が設定されます。受け入れ側は委託された資格を gss_accept_sec_context()delegated_cred_handle 引数として受け取ります。資格の委託はコンテキストのエクスポートとは異なります (コンテキストのエクスポートとインポート を参照)。その違いのひとつは、アプリケーションはその資格を一度に複数回委託できますが、コンテキストは一度に 1 つのプロセスでしか保持されません。

相互認証

ftp でファイルを公的な ftp サイトにダウンロードする場合、サイトがユーザーの ID を証明するように要求することはあっても、ユーザーがサイトの ID を証明するように要求することはありません。ところが、パスワードやクレジットカードの番号をアプリケーションに提供する場合、ユーザーは受け取り側が信頼できるサイトであることを確認したいはずです。このような場合、「相互認証」が必要です。つまり、コンテキストの起動側と受け入れ側が両方とも自身の ID を証明する必要があるということです。

コンテキスト起動側が相互認証を要求するには、gss_init_sec_context()req_flags 引数に値 GSS_C_MUTUAL_FLAG を設定します。相互認証が承認されると、ret_flags 引数にも値 GSS_C_MUTUAL_FLAG が設定されます。相互認証が要求されたが使用できない場合、結果に応じて応答するのは起動側アプリケーションの責任です。つまり、このような理由では、GSS-API はコンテキストを終了しません。機構の中には、要求されたかどうかに関わらずに相互認証を実行するものもあります。

誤順序の検出とリプレイの検出

通常、コンテキスト起動側が複数の連続するデータパケットを受け入れ側に転送する場合、到達したパケットが正しい順序であり、不必要な重複がないことをコンテキスト受け入れ側がチェックできるような機構もあります (図 1–9 を参照)。受け入れ側がこのような 2 つの状態をチェックするのは、パケットの有効性を検証するとき、あるいは、パケットをラップ解除するときです。詳細は、ラップ解除と検証 を参照してください。

図 1–9 リプレイされたメッセージと順序が正しくないメッセージ

Graphic

このような 2 つの状態を検査するように要求するには、起動側は、gss_init_sec_context() でコンテキストを起動するときに、req_flags 引数に値 GSS_C_REPLAY_FLAG または GSS_C_SEQUENCE_FLAG をビット論理和で設定する必要があります。

匿名認証

GSS-API の通常の使用においては、起動側の識別情報 (ID) はコンテキスト確立プロセスの結果として、受け入れ側に使用できるようになります。しかし、コンテキスト起動側は自身の ID をコンテキスト受け入れ側に知らせないように要求することもできます。

たとえば、医療情報が含まれているデータベースへのアクセスを提供するアプリケーションで、サービスへの制限なしのアクセスを提供している場合を想定してください。このようなサービスのクライアントは、サービスを認証したい (つまり、そこから取得できる情報の信頼性を確立したい) と希望しますが、サービスによりクライアントの識別情報が取得されることは希望しません (特定の照合に関するプライバシの問題や、メールリストなどに利用されるのを防ぐなどのため)。

匿名性を要求するには、gss_init_sec_context()req_flags 引数に GSS_C_ANON_FLAG を設定します。匿名性を使用できるかどうかをチェックするには、gss_init_sec_context() または gss_accept_sec_context()ret_flags 引数に GSS_C_ANON_FLAG が設定されているかどうかを調べます。

匿名性が有効であり、gss_accept_sec_context() または gss_inquire_context() が戻したクライアント名上で gss_display_name() が呼び出された場合、gss_display_name() は汎用的な匿名を生成します。


注 –

匿名性が要求されたが使用できない場合、適切な対処を行うのはアプリケーションの責任です。つまり、このような理由では、GSS-API はコンテキストを終了しません。


チャネルバインディング

多くのアプリケーションでは、コンテキスト起動側を適切に認証するには、基本的なコンテキスト確立だけで十分です。追加のセキュリティが必要な場合、GSS-API ではチャネルバインディングを使用します。チャネルバインディングとは、使用される特定のデータチャネル (つまり、コンテキストの起点と終点 (起動側と受け入れ側)) を識別するタグのことです。このようなタグは起動側と受け入れ側のアプリケーションに固有であるため、より有効な ID の証明となります。

チャネルバインディングは、gss_channel_bindings_struct 構造体へのポインタである gss_channel_bindings_t データ型で指定します。例 1–8 を参照してください。


例 1–8 gss_channel_bindings_t


typedef struct gss_channel_bindings_struct {
OM_uint32       initiator_addrtype;
gss_buffer_desc initiator_address;
OM_uint32       acceptor_addrtype;
gss_buffer_desc acceptor_address;
gss_buffer_desc application_data;
} *gss_channel_bindings_t;

最初の 2 つのフィールドは起動側のアドレスとアドレス型 (起動側のアドレスが送信される形式) を示します。たとえば、initiator_addrtypeGSS_C_AF_INET に設定した場合、initiator_address がインターネットアドレス形式 (つまり、IP アドレス) であることを示します。同様に、3 番目と 4 番目のフィールドは受け入れ側のアドレスとアドレス型を示します。最後のフィールド (application_data) はアプリケーションが自由に使用することができます。使用する予定がない場合は GSS_C_NO_BUFFER に設定するように習慣付けましょう。アプリケーションがアドレスを指定したくない場合、アドレス型フィールドを GSS_C_AF_NULLADDR に設定します。有効なアドレス型の値については、チャネルバインディングのアドレス型を参照してください。

このようなアドレス型は、特定のアドレス形式を示すのではなく、アドレスファミリを示します。アドレスファミリが複数の代替アドレス形式を持つ場合、どのアドレス形式を使用するかを判断できるだけの十分な情報を initiator_addressacceptor_address のフィールドに指定する必要があります。特に指定しない限り、アドレスはネットワークのバイト順 (つまり、アドレスファミリにネイティブなバイト順) で指定します。

チャネルバインディングを使用してコンテキストを確立するには、割り当てられたチャネルバインディング構造体を gss_init_sec_context()input_chan_bindings 引数で指します。gss_init_sec_context() 関数は、構造体のフィールドをオクテット文字列に連結し、この文字列から MIC (Message Integrity Code) を計算し、この MIC と gss_init_sec_context() が生成した出力トークンを結合します。次に、アプリケーションはこのトークンをコンテキスト受け入れ側に送信します。コンテキスト受け入れ側はこのトークンを受け取り、gss_accept_sec_context() を呼び出します (コンテキストの受け入れ (サーバー)を参照)。gss_accept_sec_context() は受け取ったチャネルバインディングから MIC を計算し、MIC が一致しない場合は、GSS_C_BAD_BINDINGS を戻します。

gss_accept_sec_context() は転送されたチャネルバインディングを戻すため、受け入れ側は受け取ったチャネルバインディング値に基づいて独自のセキュリティ検査を行うことができます。たとえば application_data の値をセキュアデータベースに保存しておいたコードワードと比較するなどです。しかし、多くの場合、これは冗長です。


注 –

チャネルバインディング情報の機密性を提供するかどうかは、実際の機構によって異なります。したがって、アプリケーションは、機密性が確保されたと断定できるまで、チャネルバインディングに重要な情報を含めてはなりません。機密性を使用できるかどうかを判断するには、アプリケーションが gss_init_sec_context() または gss_accept_sec_context()ret_flags 引数 (特に値 GSS_C_CONF_FLAGGSS_C_PROT_READY_FLAG) をチェックする方法もあります。ret_flags については、コンテキストの起動 (クライアント)コンテキストの受け入れ (サーバー)を参照してください。


機構は個々に、チャネルバインディングにおけるアドレスとアドレス型に追加の制限を課すことができます。たとえば、機構は、gss_init_sec_context() に指定されたチャネルバインディングの initiator_address フィールドが持つホストシステムのネットワークアドレスが正しいかどうかを検証することができるなどです。したがって、移植性のあるアプリケーションは、アドレスフィールドに正しい情報を提供するか、あるいは、アドレス情報を省略して、アドレス型として GSS_C_AF_NULLADDR を指定する必要があります。

コンテキストのエクスポートとインポート

GSS-API はコンテキストをエクスポートおよびインポートする方法を提供します。この機能の主な目的は、マルチプロセスアプリケーション (通常は、コンテキスト受け入れ側) があるプロセスから別のプロセスにコンテキストを転送できるようにすることです。たとえば、受け入れ側がコンテキスト起動側の応答を待つプロセスと、コンテキストに送信されたデータを処理するプロセスを持っている場合などです。これらの関数でコンテキストを保存および復元する方法については、test_import_export_context()を参照してください。

gss_export_sec_context() 関数は、エクスポートされるコンテキストについての情報が入ったプロセス間トークンを作成します。プロセス間トークンを参照してください。gss_export_sec_context() を呼び出す前に、このトークンを受信するバッファは GSS_C_NO_BUFFER に設定する必要があります。

次に、アプリケーションはこのトークンを他のプロセスに渡します。他のプロセスはトークンを受け取り、gss_import_sec_context() に渡します。多くの場合、アプリケーション間でトークンを渡すときに使用される関数は、プロセス間でトークンを渡すときにも使用されます。

セキュリティプロセスのインスタンスは一度に 1 つしか存在できません。gss_export_sec_context() はエクスポートされたコンテキストを無効にし、そのコンテキストハンドルを GSS_C_NO_CONTEXT に設定します。さらに、そのコンテキストに関連するプロセス規模のリソースの割り当てをすべて解除します。コンテキストのエクスポートが完了しなかった場合、gss_export_sec_context() はプロセス間トークンを戻さず、既存のセキュリティコンテキストを元のままにします。

すべての機構でコンテキストをエクスポートできるわけではありません。したがって、コンテキストをエクスポートできるかどうかを調べるには、gss_accept_sec_context() または gss_init_sec_context()ret_flags 引数をチェックします。このフラグに GSS_C_TRANS_FLAG が設定されている場合、コンテキストはエクスポートできます。コンテキストの受け入れ (サーバー)コンテキストの起動 (クライアント)を参照してください。

図 1–10 に、マルチプロセスの受け入れ側がコンテキストをエクスポートしてマルチタスクを実現している様子を示します。この例では、プロセス 1 はトークンを受け取って処理し、コンテキストレベルトークンをそのトークンから分離し、そのトークンをプロセス 2 に渡します。プロセス 2 はこのデータトークンをアプリケーション固有な方法で処理します。この図では、クライアントはすでに gss_init_sec_context() からエクスポートトークンを取得しています。クライアントはエクスポートトークンをユーザー定義関数 send_a_token() に渡します。send_a_token() は転送中のトークンがコンテキストレベルトークンまたはメッセージトークンのどちらであるかを示しています。send_a_token() はトークンをサーバーに転送します。この図には示されていませんが、おそらく、send_a_token() はスレッド間でトークンを渡すときにも使用されます。

図 1–10 コンテキストのエクスポート: マルチスレッド化された受け入れ側の例

Graphic

コンテキスト情報

GSS-API は、指定されたセキュリティコンテキスト (不完全なものであっても) についての情報を獲得する gss_inquire_context() 関数を提供します。コンテキストハンドルを指定すると、gss_inquire_context() はそのコンテキストについて次の情報を提供します。

詳細は、gss_inquire_context(3GSS) のマニュアルページを参照してください。