この節では、GSS-API を使用する安全なデータ交換を実装する方法を、一般的な手順で説明します。すべての GSS-API 関数を説明するわけではありません。その代わりに、GSS-API を使用する上で最も中心となる関数に注目します。詳細は、すべての GSS-API 関数のリスト (および GSS-API 状態コードとデータ型) が載っている付録 B 「GSS-API リファレンス」 を参照してください。また、個々の GSS-API 関数については、マニュアルページも参照してください。
簡単に理解できるように、このマニュアルでは単純なモデルを使用します。クライアントアプリケーションがリモートサーバーにデータを送信します。クライアントは直接、つまり、RPC などの転送プロトコル層を介さずに、データを送信します。付録 A 「C ベース の GSS-API サンプルプログラム」 には、サンプルプログラム (クライアントとサーバー) を示します。第 2 章「GSS-API サンプルプログラムについての概略説明」では、これらのサンプルプログラムについて段階的に説明しています。
次に、GSS-API を使用するための基本的な手順を示します。
各アプリケーション (送信側と受信側) は資格を明示的に獲得します (資格を自動的に獲得していない場合)
送信側はセキュリティコンテキストを起動し、受信側はそれを受け入れます。
送信側は転送するメッセージ (データ) にセキュリティ保護を適用します。すなわち、メッセージを暗号化するか、識別タグを付けます。送信側は保護したメッセージを転送します。
送信側はセキュリティ保護を適用しなくてもかまいません。この場合、関連するデフォルトの GSS-API セキュリティサービスだけがメッセージに適用されます。つまり、認証です。認証を使用すると、受信側は、送信側が本当に受信側の要求したとおりのアプリケーションであるかどうかを知ることができます。
受信側はメッセージを復号化し (必要であれば)、検証します (該当する場合)。
(省略可能) 確認のため、受信側は識別タグを送信側に返送します。
送信側と受信側のアプリケーションは両方とも共有セキュリティコンテキストを無効にします。必要であれば、残っている GSS-API データも解放できます。
GSS-API を使用するアプリケーションは gssapi.h ファイルをインクルード(include)します。
図 1–6 に、このプロセスの全体的な概要を示します。この図では、GSS-API が使用できる 1 つの方法しか示していません。しかし、他の場合も考えられます。
資格とは、プリンシパル名に対するアプリケーションの要求の証明を提供するデータ構造です。アプリケーションは資格を使用して、ID を確立します。資格はプリンシパルの「識別バッジ」であると考えることもできます。つまり、人、マシン、またはプログラムが本当に要求したとおりのプリンシパルであるかどうか、また多くの場合は、どのような特権を持っているかを証明する情報の集合です。
GSS-API 自身は資格を提供しません。資格は、GSS-API 関数が呼び出される前に、GSS-API の下にあるセキュリティ機構によって作成されます。たとえば、多くの場合、ユーザーはシステムにログインするときに資格を受け取ります。
1 つの GSS-API 資格は単一のプリンシパルだけに有効です。単一の資格は、その単一のプリンシパルに対して複数の (つまり、機構ごとに作成される) 要素を持つことができます。図 1–7 を参照してください。つまり、複数のセキュリティ機構を持つ 1 台のマシン上で獲得された資格は、それらの機構のサブセットだけを持つマシンに転送されるときに有効です。GSS-API は gss_cred_id_t 構造体を通じて資格にアクセスします。この構造体のことを「資格ハンドル」と呼びます。資格はアプリケーションでは意識する必要はありません。ユーザーは、与えられた資格の詳細を知っている必要はありません。
GSS_C_INITIATE
: この種類の資格は、セキュリティコンテキストを起動するだけのアプリケーションを識別します。
GSS_C_ACCEPT
: この種類の資格は、セキュリティコンテキストを受け入れるだけのアプリケーションを識別します。
GSS_C_BOTH
: この種類の資格は、セキュリティコンテキストを起動または受け入れることができるアプリケーションを識別します。
セキュリティコンテキストが確立できるようになるまでに、サーバーとクライアントはそれぞれの資格を獲得する必要があります。獲得後、資格は有効期間が満了するまで何度も使用できます。資格が満了したときは、もう一度資格を獲得し直す必要があります。クライアントが使用する資格とサーバーが使用する資格とでは、その有効期間が異なる場合があります。
GSS-API ベースのアプリケーションは、次の 2 つの方法のどちらかで資格を獲得します。
gss_acquire_cred() 関数 (または、gss_add_cred() 関数) を使用する方法
コンテキストを確立するときに、デフォルトの資格 (値 GSS_C_NO_CREDENTIAL
) を指定する方法
ほとんどの場合、コンテキスト起動側 (クライアント) はログイン時に資格を受け取るため、gss_acquire_cred() を呼び出すのはコンテキスト受け入れ側 (サーバー) だけです。したがって、コンテキスト起動側は通常、デフォルトの資格だけを指定します。コンテキスト受け入れ側は gss_acquire_cred() を使用せずに、デフォルトの資格を使用することもできます。
起動側の資格は、他のプロセスに対してその ID を証明します。一方、受け入れ側は、セキュリティコンテキストを受け入れるための資格を獲得します。ここでは、クライアントがサーバーに ftp
要求を行う場合を考えます。クライアントはログイン時からすでに資格を持っています。そして、クライアントがコンテキストを起動しようとすると、GSS-API は自動的にその資格を取り出します。しかし、サーバープログラムは要求されたサービス (ftp
) の資格を明示的に獲得します。
次に、gss_acquire_cred() の構文を示します。
OM_uint32 gss_acquire_cred ( OM_uint32 *minor_status, const gss_name_t desired_name, OM_uint32 time_req, const gss_OID_set desired_mechs, gss_cred_usage_t cred_usage, gss_cred_id_t *output_cred_handle, gss_OID_set *actual_mechs, OM_uint32 *time_rec) |
実際の機構が返す状態コード。
資格を獲得すべきプリンシパルの名前。上記例では「ftp」です。この引数は gss_import_name() で作成されます (名前を参照)。
desired_name を GSS_C_NO_NAME
に設定した場合、汎用の資格が戻されます。つまり、GSS-API のコンテキスト起動ルーチンとコンテキスト受け入れルーチンは資格に関してデフォルトの動作を使用します。言い換えると、gss_acquire_cred() に GSS_C_NO_NAME を渡すと、gss_init_sec_context() または gss_accept_sec_context() にデフォルトの資格要求 (GSS_C_NO_CREDENTIAL
) を渡したときと同じ資格が戻ります。詳細は コンテキストの起動 (クライアント) と コンテキストの受け入れ (サーバー) を参照してください。
資格が有効であるべき時間 (秒)。GSS_C_INDEFINITE
を指定すると、最大の可能な有効期間を要求することができます。
アプリケーションがこの資格で使用したい実際の機構の集合。これは gss_OID_set データ構造体であり、それぞれが適切な機構を表す 1 つまたは複数の gss_OID 構造体を持ちます。可能な限り、GSS_C_NO_OID_SET
を指定して、GSS-API からデフォルトのセットを取得してください。
この資格をどのように使用するかを示すフラグ。コンテキストを起動する場合は GSS_C_INITIATE
、コンテキストを受け入れる場合は GSS_C_ACCEPT
、または両方の場合は GSS_C_BOTH
に設定します。
この関数から戻される資格ハンドル。
この資格で使用できる機構のセット。どの機構であるかを知る必要がない場合は、NULL に設定します。
資格が実際に有効である時間 (秒)。時間が重要でない場合は、NULL に設定します。
正常に終了した場合、gss_acquire_cred() は GSS_S_COMPLETE を戻します。有効な資格を戻すことができない場合、gss_acquire_cred() は GSS_S_NO_CRED を戻します。他のエラーコードについては、gss_acquire_cred(3GSS) のマニュアルページを参照してください。資格を獲得する例については、資格の獲得(プログラムリストは server_acquire_creds()) を参照してください。
gss_add_cred() は gss_acquire_cred() と似ています。しかし gss_add_cred() は、既存の資格に基づいて新しい資格ハンドルを作成するか、既存の資格に新しい資格要素を追加することを、アプリケーションに可能にします。GSS_C_NO_CREDENTIAL
を既存の資格として指定した場合、gss_add_cred() はデフォルトの動作に基づいて新しい資格を作成します。詳細は、gss_add_cred(3GSS) のマニュアルページを参照してください。
前述のとおり、GSS-API がセキュリティの提供において行う最も重要な 2 つの仕事は、セキュリティコンテキストを作成することと、データを保護することです。必要な資格を取得した後、アプリケーションはセキュリティコンテキストを確立します。このためには、一方のアプリケーション (通常はクライアント) がコンテキストを起動して、もう一方のアプリケーション (通常はサーバー) がそのコンテキストを受け入れます。ピア間で複数のコンテキストが存在してもかまいません。
通信中のアプリケーションは、認証トークンを交換することによって、結合セキュリティコンテキストを確立します。セキュリティコンテキストは、2 つのアプリケーション間で共有される情報が入っている一対の GSS-API データ構造体です。この情報は、各アプリケーションの (セキュリティにおける) 状態を記述します。セキュリティコンテキストはデータの保護のために必要です。
アプリケーションとリモートピア間でのセキュリティコンテキストの起動は、gss_init_sec_context() 関数で行います。成功した場合、gss_init_sec_context() 関数は確立中のコンテキストのコンテキストハンドルと、受け入れ側に送信するコンテキストレベルトークンを戻します。しかし、gss_init_sec_context() を呼び出す前に、クライアントは次のことを行う必要があります。
必要であれば、gss_acquire_cred() で資格を獲得します。しかし、通常、クライアントはログイン時に資格を受け取っているため、その場合、この手順は飛ばすことができます。
gss_import_name() で、サーバー名を GSS-API 内部形式にインポートします。名前と gss_import_name() についての詳細は、名前を参照してください。
gss_init_sec_context() を呼び出すとき、通常、クライアントは次の引数値を渡します。
GSS_C_NO_CREDENTIAL
を cred_handle 引数に渡して、デフォルトの資格を示します。
GSS_C_NULL_OID
を mech_type 引数に渡して、デフォルトの機構を示します。
GSS_C_NO_CONTEXT
を context_handle 引数に渡して、初期コンテキストが NULL であることを示します。gss_init_sec_context() は通常ループ内で呼び出されるため、後続の呼び出しは以前の呼び出しで戻されたコンテキストハンドルを渡す必要があります。
GSS_C_NO_BUFFER
を input_token 引数に渡して、トークンが最初は空であることを示します。あるいは、アプリケーションは length が 0 に設定されている gss_buffer_desc オブジェクトへのポインタを渡すこともできます。
gss_import_name() で GSS-API 内部形式にインポートされたサーバー名。
アプリケーションは必ずしもこのようなデフォルト値を使用する必要はありません。さらに、クライアントは 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) のマニュアルページを参照してください。
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 ) |
実際の機構から戻される状態コード。
アプリケーションの資格ハンドル。デフォルトの資格を使用することを示すには、GSS_C_NO_CREDENTIAL
に初期化する必要があります。
戻すべきコンテキストハンドル。ループが始まる前には、GSS_C_NO_CONTEXT
に設定する必要があります。
接続先のプリンシパルの名前。たとえば、「nfs@machinename」などです。
使用されるセキュリティ機構。GSS-API が提供するデフォルトを取得するには、GSS_C_NO_OID
に設定します。
このコンテキストで要求される追加のサービスまたはパラメータを示すフラグ。req_flags フラグは次のようにビット論理和をとって、希望のビットマスク値を作成する必要があります。
GSS_C_MUTUAL_FLAG | GSS_C_DELEG_FLAG |
起動側の資格を委託できるように要求します。委託を参照してください。
相互認証を要求します。相互認証を参照してください。
繰り返しメッセージを検出するように要求します。誤順序の検出とリプレイの検出を参照してください。
誤順序メッセージを検出するように要求します。誤順序の検出とリプレイの検出を参照してください。
転送されるメッセージに機密性サービスを適用するように、つまり、メッセージを暗号化するように要求します。機密性が許可されない場合、データ起点認証と (GSS_C_INTEG_FLAG
が偽でなければ) 整合性サービスだけを適用できます。
メッセージに整合性サービスを適用するように、つまり、メッセージに MIC を付けて有効性を保証するように要求します。
起動側が匿名のままであるように要求します。匿名認証を参照してください。
コンテキストが有効であるべき時間 (秒)。デフォルトを要求するには、0 に設定します。
セキュリティコンテキストに接続された特定のピアツーピアのチャネル識別情報。チャネルバインディングについての詳細は、チャネルバインディングを参照してください。チャネルバインディングを使用しない場合は、GSS_C_NO_CHANNEL_BINDINGS
に設定します。
コンテキスト受け入れ側から受信したトークン (もしあれば)。関数が呼び出される前に、GSS_C_NO_BUFFER
に初期化する (あるいは、長さフィールドを 0 に設定する) 必要があります。
コンテキストで実際に使用される機構。どの機構が使用されるかを知る必要がない場合は、NULL に設定します。
受け入れ側に送信すべきトークン。
このコンテキストで要求された、追加のサービスまたはパラメータを示すフラグ。ret_flags フラグは次のようにビット論理積をとって、戻されたビットマスク値をテストする必要があります。
if (ret_flags & GSS_C_CONF_FLAG) confidentiality = TRUE; |
真の場合、起動側の資格が委託できることを示します。委託を参照してください。
真の場合、相互認証が使用できることを示します。相互認証を参照してください。
真の場合、繰り返しメッセージの検出が有効であることを示します。誤順序の検出とリプレイの検出を参照してください。
真の場合、誤順序メッセージの検出が有効であることを示します。誤順序の検出とリプレイの検出を参照してください。
真の場合、転送されるメッセージに機密性サービスを適用できます。つまり、メッセージを暗号化できます。機密性が許可されない場合、データ起点認証と (GSS_C_INTEG_FLAG が偽でなければ) 整合性サービスだけを適用できます。
真の場合、メッセージに整合性サービスを適用できます。つまり、メッセージに MIC (Message Integrity Code) を付けて有効性を保証できます。
真の場合、コンテキスト起動側が匿名のままであることを示します。匿名認証を参照してください。
コンテキストの確立に時間がかかり、完了するまで、クライアントが待機する場合もあります。コンテキストが完全に確立されていない場合でも、gss_init_sec_context() は、コンテキストが完全に確立された後にどの保護サービスが使用できるかを (もしあれば) 示すことができます。したがって、アプリケーションはデータをバッファに格納しておいて、コンテキストが完全に確立された後で、バッファに格納しておいたデータを送信できます。
ret_flags が GSS_C_PROT_READY_FLAG を示す場合、コンテキストが完全に確立されていない場合でも (つまり、gss_init_sec_context() が GSS_S_CONTINUE_NEEDED を戻す場合でも)、GSS_C_CONF_FLAG と GSS_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_FLAG と GSS_C_INTEG_FLAG フラグを調べて、どのメッセージ毎サービスを使用できるかを判断する必要があります。
このコンテキストがエクスポートできるかどうかを示します。コンテキストのインポートとエクスポートについての詳細は、コンテキストのエクスポートとインポートを参照してください。
資格が有効である時間 (秒)。時間が重要でない場合は、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_acquire_cred() から戻された資格ハンドル。あるいは、GSS_C_NO_CREDENTIAL
を cred_handle 引数に渡して、デフォルトの資格を示します。
GSS_C_NO_CONTEXT
を context_handle 引数に渡して、初期コンテキストが NULL であることを示します。gss_init_sec_context() は通常ループ内で呼び出されるため、後続の呼び出しは以前の呼び出しで戻されたコンテキストハンドルを渡す必要があります。
クライアントから受け取ったコンテキストトークンを input_token 引数に渡します。
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) のマニュアルページを参照してください。
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) |
実際の機構から戻される状態コード。
起動側に戻すべきコンテキストハンドル。ループが始まる前には、GSS_C_NO_CONTEXT
に設定する必要があります。
受け入れ側が (通常は、gss_acquire_cred() で) 獲得した資格のハンドル。GSS_C_NO_CREDENTIAL
に初期化すると、デフォルトの資格を使用することを示すことができます。デフォルトの資格が定義されていない場合、GSS_C_NO_CRED を戻します。
(注: プリンシパル名として GSS_C_NO_NAME
が渡された場合、gss_acquire_cred() は gss_accept_sec_context() がデフォルトの資格として扱うような資格を生成します。)
コンテキスト起動側から受け取ったトークン。
セキュリティコンテキストに接続された特定のピアツーピアチャネル識別情報。チャネルバインディングについての詳細は、チャネルバインディングを参照してください。チャネルバインディングを使用しない場合は、GSS_C_NO_CHANNEL_BINDINGS
に設定します。
起動しているプリンシパルの名前。たとえば、nfs@machinename などです。プリンシパルの名前が重要でない場合は、NULL に設定します。
使用されるセキュリティ機構。どの機構が使用されるかが重要でない場合は、NULL に設定します。
起動側に送信すべきトークン。関数が呼び出される前に、GSS_C_NO_BUFFER
に初期化する (あるいは、長さフィールドを 0 に設定する) 必要があります。長さが 0 の場合、送信する必要のあるトークンはありません。
このコンテキストで要求された追加のサービスまたはパラメータを示すフラグ。ret_flags フラグは次のようにビット論理積をとって、戻されたビットマスク値をテストする必要があります。
if (ret_flags & GSS_C_CONF_FLAG) confidentiality = TRUE; |
起動側の資格が delegated_cred_handle 引数経由で委託できることを示します。委託を参照してください。
相互認証が使用できることを示します。相互認証を参照してください。
繰り返しメッセージの検出が有効であることを示します。誤順序の検出とリプレイの検出を参照してください。
誤順序メッセージの検出が有効であることを示します。誤順序の検出とリプレイの検出を参照してください。
真の場合、転送されるメッセージに機密性サービスを適用できます。つまり、メッセージを暗号化できます。機密性が許可されない場合、データ起点認証と (GSS_C_INTEG_FLAG が偽でなければ) 整合性サービスだけを適用できます。
真の場合、メッセージに整合性サービスを適用できます。つまり、メッセージに MIC (Message Integrity Code) を付けて有効性を保証できます。
コンテキスト起動側が匿名のままであることを示します。匿名認証を参照してください。
コンテキストの確立に時間がかかる場合、コンテキストが完全に確立されていない場合でも、受け入れ側がコンテキスト関連のデータを処理できるように、クライアントは起動パスに十分な情報を送信できます。このような状況では、受け入れ側は情報がどのように保護されているかを (もしあれば) 知る必要があります。
GSS_C_PROT_READY_FLAG が真の場合、GSS_C_CONF_FLAG と GSS_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_FLAG と GSS_C_INTEG_FLAG フラグを調べて、どのメッセージ毎サービスを使用できるかを判断する必要があります。
真の場合、このコンテキストがエクスポートできることを示します。コンテキストのインポートとエクスポートについての詳細は、コンテキストのエクスポートとインポートを参照してください。
コンテキストが有効である時間 (秒)。時間が重要でない場合は、NULL に設定します。
コンテキスト起動側から受け取った資格 (つまり、クライアントの資格) の資格ハンドル。受け入れ側がプロクシとして動作するように起動側が要求した場合だけ、つまり、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 と識別するかは、機構によって異なります。
委託が許可されると、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 つの状態をチェックするのは、パケットの有効性を検証するとき、あるいは、パケットをラップ解除するときです。詳細は、ラップ解除と検証 を参照してください。
このような 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 を参照してください。
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_addrtype を GSS_C_AF_INET
に設定した場合、initiator_address がインターネットアドレス形式 (つまり、IP アドレス) であることを示します。同様に、3 番目と 4 番目のフィールドは受け入れ側のアドレスとアドレス型を示します。最後のフィールド (application_data) はアプリケーションが自由に使用することができます。使用する予定がない場合は GSS_C_NO_BUFFER
に設定するように習慣付けましょう。アプリケーションがアドレスを指定したくない場合、アドレス型フィールドを GSS_C_AF_NULLADDR
に設定します。有効なアドレス型の値については、チャネルバインディングのアドレス型を参照してください。
このようなアドレス型は、特定のアドレス形式を示すのではなく、アドレスファミリを示します。アドレスファミリが複数の代替アドレス形式を持つ場合、どのアドレス形式を使用するかを判断できるだけの十分な情報を initiator_address と acceptor_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_FLAG と GSS_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() はスレッド間でトークンを渡すときにも使用されます。
GSS-API は、指定されたセキュリティコンテキスト (不完全なものであっても) についての情報を獲得する gss_inquire_context() 関数を提供します。コンテキストハンドルを指定すると、gss_inquire_context() はそのコンテキストについて次の情報を提供します。
コンテキスト起動側の名前
コンテキスト受け入れ側の名前
コンテキストが有効である時間 (秒)
コンテキストで使用されるセキュリティ機構
いくつかのコンテキストパラメータフラグ。これらのフラグは gss_accept_sec_context() 関数の ret_flags 引数と同じで(コンテキストの受け入れ (サーバー)を参照)、委託や相互認証などをカバーします。
照会側アプリケーションがコンテキスト起動側であるかどうかを示すフラグ
コンテキストが完全に確立されているかどうかを示すフラグ
詳細は、gss_inquire_context(3GSS) のマニュアルページを参照してください。
ピア間 (つまり、クライアントとサーバー間) でコンテキストが確立された後、メッセージは送信する前に保護できます。
コンテキストを確立しメッセージを送信するだけの場合、最も基本的な GSS-API 保護である「認証」が使用されます。認証を使用すると、受信側は、送信側であるべきと要求されているプリンシパルからのメッセージであるかどうかを知ることができます。使用される実際のセキュリティ機構によって異なりますが、GSS-API は次の 2 つの保護も提供します。
整合性。メッセージ整合性コード (MIC) をメッセージに添付します。MIC を使用すると、受信側は受信したメッセージが送信されたメッセージと同じであることをチェックできます。MIC を生成するのは、GSS-API の gss_get_mic() 関数です。
機密性。MIC の添付に加えて、メッセージを暗号化します。暗号化を実行するのは、GSS-API の gss_wrap() 関数です。
図 1–11 に、2 つの関数の違いを示します。
どちらの関数を使用するかは、ユーザーの必要性によって異なります。gss_wrap() は整合性サービスも含むため、多くのプログラムは gss_wrap() を使用します。機密性サービスを使用できるかどうかをテストするには、機密性サービスを付けて (または、付けずに) gss_wrap() を呼び出します。使用例は、データの送信(プログラムリストは call_server()) を参照してください。しかし、gss_get_mic() で保護されたメッセージは受信側がラップ解除する必要がないため、gss_wrap() を使用するときよりも CPU サイクルを節約できます。したがって、機密性が必要ないプログラムは gss_get_mic() でメッセージを保護する傾向にあります。
gss_get_mic() を使用すると、プログラムは暗号化 MIC をメッセージに追加できます。受信側は gss_verify_mic() を呼び出し、この MIC をチェックすることによって、受信したメッセージが送信されたメッセージと同じであるかどうかを調べることができます。次に、gss_get_mic() の形式を示します。
OM_uint32 gss_get_mic ( OM_uint32 *minor_status, const gss_ctx_id_t context_handle, gss_qop_t qop_req, const gss_buffer_t message_buffer, gss_buffer_t msg_token) |
実際の機構から戻される状態コード。
メッセージが送信されるコンテキスト。
要求する QOP (保護品質)。MIC を生成するときに使用される暗号化アルゴリズムです。移植性のためには、アプリケーションは可能な限りデフォルトの QOP を指定するべきです。つまり、この引数に GSS_C_QOP_DEFAULT
を設定します。デフォルト以外の QOP の指定については、付録 C を参照してください。
MIC をタグ付けするメッセージ。この引数は gss_buffer_desc オブジェクトの形式である必要があります (文字列および類似のデータを参照)。使用し終わったときには、gss_release_buffer() で解放する必要があります。
メッセージと MIC が入っているトークン。使用し終わったときには、gss_release_buffer() で解放する必要があります。
gss_get_mic() はメッセージと MIC を別々に出力します。これは、gss_wrap() とは異なります。gss_wrap() は両方を一緒にして出力します。このように別々に出力するということは、送信側アプリケーションがメッセージと MIC の両方を送信するためにアレンジを行う必要があるということを意味します。さらに重要なことは、受信側アプリケーションがメッセージと MIC を受信および区別できる必要があるということです。メッセージと MIC を適切に処理するには、次のような方法があります。
プログラム制御 (つまり、状態) を通じて。受信側アプリケーションは受信関数を 2 回呼び出す (つまり、1 回目はメッセージを取得するため、2 回目はメッセージの MIC を取得するため) ことをあらかじめ知ることができます。
フラグを通じて。送信と受信の関数はどの種類のトークンを含めるかをフラグで示すことができます。
メッセージと MIC の両方を入れることができるユーザー定義トークン構造体を通じて。
正常に終了した場合、gss_get_mic() は GSS_S_COMPLETE を戻します。指定した QOP が有効でなかった場合、gss_get_mic() は GSS_S_BAD_QOP を戻します。詳細は、gss_get_mic(3GSS) のマニュアルページを参照してください。
メッセージは gss_wrap() 関数で「ラップ」することも可能です。gss_get_mic() と同様に、gss_wrap() は MIC を提供します。機密性が要求される場合 (かつ、実際の機構で使用できる場合)、gss_wrap() はさらにメッセージを暗号化します。メッセージの受信側は gss_unwrap() でメッセージを「ラップ解除」します。次に、gss_wrap() の形式を示します。
OM_uint32 gss_wrap ( OM_uint32 *minor_status, const gss_ctx_id_t context_handle, int conf_req_flag, gss_qop_t qop_req const gss_buffer_t input_message_buffer, int *conf_state, gss_buffer_t output_message_buffer ) |
実際の機構から戻される状態コード。
このメッセージが送信されるコンテキスト。
機密性サービス (暗号化) を要求するためのフラグ。0 以外の場合、機密性と整合性の両方を要求します。0 の場合、整合性サービスだけを要求します。
要求する QOP (保護品質)。MIC を生成するときと暗号化を行うときに使用される暗号化アルゴリズムです。移植性のためには、アプリケーションは可能な限りデフォルトの QOP を指定するべきです。つまり、この引数に GSS_C_QOP_DEFAULT
を設定します。デフォルト以外の QOP の指定については、付録 C 「OID の指定」 を参照してください。
ラップするメッセージ。この引数は gss_buffer_desc オブジェクトの形式である必要があります (文字列および類似のデータを参照)。使用し終わったときには、gss_release_buffer() で解放する必要があります。
関数が戻ったときに、機密性が適用されたかどうかを示すフラグ。0 以外の場合、機密性、メッセージ起点認証、および整合性サービスが適用されたことを示します。0 の場合、メッセージ起点認証と整合性だけが適用されたことを示します。必要ない場合は、NULL を指定します。
ラップしたメッセージ用のバッファ。アプリケーションがメッセージを処理した後には、gss_release_buffer() で解放する必要があります。
gss_get_mic() とは違い、gss_wrap() はメッセージと MIC を一緒にラップし、1 つの出力メッセージにします。したがって、メッセージを転送する関数は 1 回呼び出すだけでかまいません。メッセージの受信側では、gss_unwrap() でメッセージを抽出します。なお、MIC はアプリケーションからは見えません。
メッセージが正常にラップされた場合、gss_wrap() は GSS_S_COMPLETE を戻します。要求した QOP が有効でなかった場合、gss_wrap() は GSS_S_BAD_QOP を戻します。gss_wrap() の使用例は、データの送信(プログラムリストは call_server()を参照してください。詳細は、gss_wrap(3GSS) のマニュアルページを参照してください。
gss_wrap() でメッセージをラップすると、メッセージのサイズが増加します。保護されたメッセージパケットは、転送プロトコルを通過できるぐらいのサイズである必要があります。したがって、GSS-API の gss_wrap_size_limit 関数を使用して、ラップしても転送プロトコルを通過できるメッセージの最大サイズを計算します。この最大サイズを超える場合、アプリケーションは gss_wrap() を呼び出す前にメッセージを分割できます。メッセージを実際にラップする前にはラップサイズの制限値をチェックするように習慣付けましょう。
サイズの増加量は次の 2 つの影響を受けます。
メッセージをラップするためにどの QOP (保護品質) アルゴリズムを使用するか。GSS-API の実装によってデフォルトの QOP が異なるため、デフォルトの QOP を指定した場合でも、ラップされたメッセージのサイズは異なる可能性があります。図 1–12 に、この様子を示します。
機密性を呼び出すかどうか。機密性を適用するかどうかに関わらず、gss_wrap() は転送されるメッセージに MIC を添付するため、メッセージのサイズは増加します。しかし、メッセージを暗号化すると (機密性を適用すると)、メッセージのサイズはさらに増加します。図 1–13 に、この様子を示します。
次に、gss_wrap_size_limit() の形式を示します。
OM_uint32 gss_wrap_size_limit ( OM_uint32 *minor_status, const gss_ctx_id_t context_handle, int conf_req_flag, gss_qop_t qop_req, OM_uint32 req_output_size, OM_uint32 *max_input_size) |
実際の機構から戻される状態コード。
データが転送されるコンテキスト。
機密性サービス (暗号化) を要求するためのフラグ。0 以外の場合、機密性と整合性の両方を要求します。0 の場合、整合性サービスだけを要求します。
要求する QOP (保護品質)。MIC を生成するときと暗号化を行うときに使用される暗号化アルゴリズムです。移植性のためには、アプリケーションは可能な限りデフォルトの QOP を指定するべきです。つまり、この引数に GSS_C_QOP_DEFAULT
を設定します。デフォルト以外の QOP の指定については、付録 C 「OID の指定」 を参照してください。
指定した転送プロトコルが処理できるデータ片の最大サイズ (型は int)。この情報は、ユーザーが自ら提供する必要があります。つまり、GSS-API はプロトコルに依存しないため、どのプロトコルが使用されるのかを知る方法がありません。
関数から戻される値。つまり、ラップしたときに req_output_size を超えないような、ラップしていないメッセージの最大サイズ。
正常に終了した場合、gss_wrap_size_limit() は GSS_S_COMPLETE を戻します。指定した QOP が有効でなかった場合、gss_wrap_size_limit() は GSS_S_BAD_QOP を戻します。gss_wrap_size_limit() でオリジナルのメッセージの最大サイズを求める例 (機密性を使用する場合と使用しない場合の両方) については、call_server()を参照してください。
この機能は gss_wrap() を呼び出した時点でのシステムリソースの可用性に依存するため、この呼び出しが正常に終了したとしても、必ずしも、gss_wrap() が max_input_size 以下のバイトの長さを持つメッセージを保護できるとは保証できません。詳細は、gss_wrap_size_limit(3GSS) のマニュアルページを参照してください。
ラップされたメッセージを受信した後は、gss_unwrap() でメッセージをラップ解除する必要があります。gss_unwrap() は、ラップされたメッセージに埋め込まれている MIC に対してメッセージを自動的に検証します。送信側がメッセージをラップしなかったが、gss_get_mic() で MIC を生成している場合は、gss_verify_mic() で、その MIC に対して受信したメッセージを検証できます。後者の場合、受け入れ側はメッセージと MIC の両方を受信するようアレンジする必要があります。
次に、gss_unwrap() の形式を示します。
OM_uint32 gss_unwrap ( OM_uint32 *minor_status, const gss_ctx_id_t context_handle, const gss_buffer_t input_message_buffer, gss_buffer_t output_message_buffer, int *conf_state gss_qop_t *qop_state) |
実際の機構から戻される状態コード。
このメッセージが送信されるコンテキスト。
ラップされたメッセージ。この引数は gss_buffer_desc オブジェクトの形式である必要があります (文字列および類似のデータを参照)。使用し終わったときには、gss_release_buffer() で解放する必要があります。
ラップ解除したメッセージ用のバッファ。アプリケーションがラップ解除したメッセージを処理した後には、gss_release_buffer() でこのバッファを解放する必要があります。この引数も gss_buffer_desc オブジェクトです。
機密性が適用されたかどうかを示すフラグ。0 以外の場合、機密性、メッセージ起点認証、および整合性サービスが適用されたことを示します。0 の場合、メッセージ起点認証と整合性だけが適用されたことを示します。必要ない場合は、NULL を指定します。
使用する QOP (保護品質)。MIC を生成するときと暗号化を行うときに使用される暗号化アルゴリズムです。必要ない場合は、NULL を指定します。
メッセージが正常にラップ解除された場合、gss_unwrap() は GSS_S_COMPLETE を戻します。MIC に対してメッセージを検証できなかった場合、gss_unwrap() は GSS_S_BAD_SIG を戻します。
メッセージがラップ解除された場合、あるいは、初めからメッセージがラップされていない場合は、gss_verify_mic() でメッセージを検証できます。次に、gss_verify_mic() の形式を示します。
OM_uint32 gss_verify_mic ( OM_uint32 *minor_status, const gss_ctx_id_t context_handle, const gss_buffer_t message_buffer, const gss_buffer_t token_buffer, gss_qop_t qop_state) |
実際の機構から戻される状態コード。
メッセージが送信されるコンテキスト。
受信したメッセージ。この引数は gss_buffer_desc オブジェクトの形式である必要があります (文字列および類似のデータを参照)。アプリケ-ションが使用し終わったときには、gss_release_buffer() で解放する必要があります。
受信した MIC が入っているトークン。この引数は gss_buffer_desc オブジェクトの形式である必要があります ( 文字列および類似のデータを参照)。アプリケーションが使用し終わったときには、gss_release_buffer() で解放する必要があります。
MIC を生成するときに適用される QOP (保護品質)。必要ない場合は、NULL を指定します。
メッセージが正常に検証された場合、gss_verify_mic() は GSS_S_COMPLETE を戻します。MIC に対してメッセージを検証できなかった場合、gss_verify_mic() は GSS_S_BAD_SIG を戻します。
転送されたメッセージをラップ解除または検証した後、受信側は送信側に確認を送信することもできます。つまり、そのメッセージの MIC を返送します。送信側がラップはしなかったが gss_get_mic() で MIC をタグ付けしているメッセージの場合を考えます。図 1–14 に、このプロセスの様子を示します。
起動側は gss_get_mic() でメッセージにタグ付けします。
起動側はメッセージと MIC を受け入れ側に送信します。
受け入れ側は gss_verify_mic() でメッセージを検証します。
受け入れ側は MIC を起動側に返送します。
起動側は gss_verify_mic() で、オリジナルのメッセージに対して受信した MIC を検証します。
ラップされたデータの場合、gss_unwrap() 関数はメッセージと MIC を別々に生成しません。したがって、受信側は、受信した (およびラップ解除した) メッセージから MIC を生成する必要があります。図 1–15 に、このプロセスの様子を示します。
起動側は gss_wrap() でメッセージをラップします。
起動側はラップしたメッセージを送信します。
受け入れ側は gss_unwrap() でメッセージをラップ解除します。
受け入れ側は gss_get_mic() でラップ解除されたメッセージの MIC を生成します。
受け入れ側は抽出した MIC を起動側に返信します。
起動側は gss_verify_mic() で、オリジナルのメッセージに対して受信した MIC を検証します。
すべてのメッセージを送受信し、終了した後、起動側と受け入れ側のアプリケーションは両方とも gss_delete_sec_context() で共有コンテキストを破壊する必要があります。gss_delete_sec_context() はコンテキストに関連するローカルのデータ構造体を削除します。次に、gss_delete_sec_context() の形式を示します。
OM_uint32 gss_delete_sec_context ( OM_uint32 *minor_status, gss_ctx_id_t *context_handle, gss_buffer_t output_token) |
実際の機構から戻される状態コード。
削除されるコンテキスト。
GSS_C_NO_BUFFER
に設定します。
詳細は、gss_delete_sec_context(3GSS) のマニュアルページを参照してください。
用心のため、アプリケーションは GSS-API データ用に割り当てたデータ領域をすべて解放するべきです。このような関数には、gss_release_buffer()、gss_release_cred()、gss_release_name()、および gss_release_oid_set() があります。詳細は、それぞれのマニュアルページを参照してください。