2 つのピア間でコンテキストが確立されたあと、メッセージを送信する前にそのメッセージを保護できます。
コンテキストの確立時に使用されるのは、もっとも基本的な GSS-API 保護である 「認証」だけです。実際のセキュリティー機構によって異なりますが、GSS-API は次の 2 つの保護も提供します。
整合性 – gss_get_mic() 関数によってメッセージに対するメッセージ整合性コード (MIC) が生成されます。受信側は、MIC を検査することで、受信したメッセージが送信されたメッセージと同じかどうかを確認できます。
機密性 – MIC の使用に加え、メッセージが暗号化されます。暗号化を実行するのは、GSS-API の gss_wrap() 関数です。
gss_get_mic() と gss_wrap() の違いを、次の図に示します。gss_get_mic() を使用した場合、受信側はメッセージが変更されていないことを示すタグを受け取ります。gss_wrap() を使用した場合、受信側は暗号化されたメッセージとタグを受け取ります。
使用すべき関数はユーザーの状況に応じて異なります。gss_wrap() は整合性サービスも含むため、多くのプログラムは gss_wrap() を使用します。プログラムは、機密性サービスが利用可能かどうかを判定できます。続いてプログラムは、その利用可能性に応じて、機密性を指定して、あるいは指定しないで、gss_wrap()を呼び出すことができます。使用例については、「メッセージのラップと送信」を参照してください。ただし、gss_get_mic() を使用するとメッセージをラップ解除する必要がないため、gss_wrap() を使用する場合よりも CPU サイクルを節約できます。したがって、機密性が必要ないプログラムは 、gss_get_mic() でメッセージを保護する可能性があります。
gss_get_mic() を使用すると、プログラムは暗号化 MIC をメッセージに追加できます。受信側は、gss_verify_mic() でメッセージの MIC を検査できます。
gss_get_mic() は gss_wrap() とは対照的に、メッセージと MIC を別々に出力します。この分離は、送信側アプリケーションがメッセージと対応する MIC の両方を送信する必要があることを意味します。さらに重要なのは、受信側がメッセージと MIC を区別できる必要がある、という点です。メッセージと MIC を適切に処理するには、次のいずれかの方法を使用します。
プログラム制御 (つまり、状態) を通じて。受信側アプリケーションは受信関数を 2 回呼び出す (つまり、1 回目はメッセージを取得するため、2 回目はメッセージの MIC を取得するため) ことをあらかじめ知ることができます。
フラグを通じて。送信側と受信側は、どの種類のトークンを含めるかをフラグで示すことができます。
メッセージと MIC の両方を含むユーザー定義トークン構造体を通じて。
gss_get_mic() が正常終了すると、GSS_S_COMPLETE が返されます。指定された QOP が有効でない場合、GSS_S_BAD_QOP が返されます。詳細は、gss_get_mic(3GSS) を参照してください。
メッセージは、gss_wrap() 関数でラップすることが可能です。gss_get_mic() と同様に、gss_wrap() は MIC を提供します。また、機密性が要求され、かつ実際の機構で利用可能である場合には、gss_wrap() は指定されたメッセージの暗号化も行います。メッセージの受信側は gss_unwrap() でメッセージをラップ解除します。
gss_wrap() は gss_get_mic() とは違い、メッセージと MIC をいっしょにラップし、1 つの出力メッセージにします。このバンドルを送信する関数の呼び出しは、1 回だけですみます。これに対し、gss_unwrap() はメッセージを抽出します。MIC はアプリケーションからは見えません。
メッセージが正常にラップされた場合、gss_wrap() は GSS_S_COMPLETE を戻します。要求された QOP が有効でない場合、GSS_S_BAD_QOP が返されます。gss_wrap() の使用例については、「メッセージのラップと送信」を参照してください。
gss_wrap() でメッセージをラップすると、送信すべきデータのサイズが増加します。保護されたメッセージパケットは、指定された転送プロトコルを通過するのに適したサイズである必要があります。したがって、GSS-API は関数 gss_wrap_size_limit() を提供しています。 gss_wrap_size_limit() は、プロトコルにとって大きすぎないサイズにラップ可能なメッセージの最大サイズを計算します。この最大サイズを超える場合、アプリケーションは gss_wrap() を呼び出す前にメッセージを分割できます。メッセージを実際にラップする前にラップサイズの制限値を必ず検査してください。
変形を行うためにどの QOP アルゴリズムを使用するか
機密性を呼び出すかどうか
デフォルトの QOP は、GSS-API の実装ごとに異なる可能性があります。したがって、デフォルトの QOP を指定した場合でも、ラップ後のメッセージのサイズが異なる可能性があります。この可能性を示したのが次の図です。
機密性を適用するかどうかにかかわらず、gss_wrap() によってメッセージのサイズが増加します。gss_wrap() は、転送メッセージ内に MIC を埋め込みます。しかし、メッセージを暗号化すると (機密性を適用すると)、メッセージのサイズはさらに増加します。このプロセスを示したのが次の図です。
gss_wrap_size_limit() が正常終了すると、GSS_S_COMPLETE が返されます。指定された QOP が有効でない場合、GSS_S_BAD_QOP が返されます。gss_wrap_size_limit() で元のメッセージの最大サイズを求める例については、「メッセージのラップと送信」を参照してください。
この呼び出しが正常に終了したとしても、gss_wrap() が max-input-size バイトの長さを持つメッセージを必ず保護できるという保証はありません。この機能は、gss_wrap() の呼び出し時点で必要なシステムリソースが利用可能かどうかに依存します。詳細は、gss_wrap_size_limit(3GSS) のマニュアルページを参照してください。
コンテキスト起動側がコンテキスト受け入れ側に一連のデータパケットを順次転送する際、一部の機構では、その順序が正しいかどうかをコンテキスト受け入れ側が検査できるようになっています。これらの検査には、「パケットが正しい順序で到着したか」、「パケットが不必要に重複していないか」が含まれます。次の図を参照してください。受け入れ側がこれら 2 つの状態を検査するのは、パケットの検証時とパケットのラップ解除時です。詳細は、「メッセージのラップ解除」を参照してください。
起動側は gss_init_sec_context() で順序を検査できます。それには、GSS_C_REPLAY_FLAG
または GSS_C_SEQUENCE_FLAG
を論理 OR で req_flags 引数に設定します。
受信側は、転送メッセージのラップ解除後または検証後に、確認を送信側に返すことができます。つまり、そのメッセージの MIC を返送します。送信側がラップはしなかったが gss_get_mic() で MIC をタグ付けしているメッセージの場合を考えます。実行手順 (図 4–9) は次のようになります。
起動側は gss_get_mic() でメッセージにタグ付けします。
起動側はメッセージと MIC を受け入れ側に送信します。
受け入れ側は gss_verify_mic() でメッセージを検証します。
受け入れ側は MIC を起動側に返送します。
起動側は gss_verify_mic() で、元のメッセージに対して受信した MIC を検証します。
ラップされたデータの場合、gss_unwrap() 関数はメッセージと MIC を別々に生成しません。したがって、受信側は、受信した (およびラップ解除した) メッセージから MIC を生成する必要があります。実行手順 (図 4–10) は次のようになります。
起動側は gss_wrap() でメッセージをラップします。
起動側はラップしたメッセージを送信します。
受け入れ側は gss_unwrap() でメッセージをラップ解除します。
受け入れ側は gss_get_mic() でラップ解除されたメッセージの MIC を生成します。
受け入れ側は抽出した MIC を起動側に返信します。
起動側は gss_verify_mic() で、元のメッセージに対して受信した MIC を検証します。
アプリケーションは、GSS-API データ用に割り当てられたすべてのデータ領域を解放する必要があります。これに関係する関数は、gss_release_buffer(3GSS)、gss_release_cred(3GSS)、gss_release_name(3GSS)、および gss_release_oid_set(3GSS) です。