GSS-API のプログラミング

第 1 章 GSS-API の概要

Generic Security Standard Application Programming Interface (GSS-API) は、ピアとなるアプリケーションに送信されるデータを保護する方法をアプリケーションに提供します。通常、ピアとなるアプリケーションとは、同じマシン上のクライアントから別のマシン上のサーバーまで、様々な可能性があります。この章では、次の内容について説明します。

GSS-API の紹介

名前が示すとおり、GSS-API を使用すると、プログラマはセキュリティの点で汎用的なアプリケーションを作成できます。つまり、特定のプラットフォーム、セキュリティ機構、保護の種類、または転送プロトコル向けに特定のセキュリティ実装を施す必要はありません。GSS-API を実装したアプリケーションはセキュリティを制御できます。しかし、GSS-API を使用するプログラマは、ネットワークデータを保護する方法についての詳細を知らなくてもプログラムの作成を行うことができます。したがって、GSS-API を使用するプログラムはネットワークセキュリティに関して移植性がより高くなります。この移植性が Generic Security Standard API の最も優れた特徴です。

GSS-API 自身はセキュリティサービスを実際に提供しません。GSS-API はセキュリティサービスを汎用的な方法で呼び出し側に提供するためのフレームワークであり、実際の機構やテクノロジなど (Kerberos v5 や公開鍵テクノロジなど) を幅広くサポートできます。図 1–1 を参照してください 。

図 1–1 GSS-API 層

アプリケーションとセキュリティ機構層の間に、GSS-API とプロトコル層が存在するダイアグラムを表示しています。

GSS-API の主な機能は簡単に言うと次の 2 つです。

  1. セキュリティコンテキストを作成し、アプリケーション間でデータを受け渡します。コンテキストとは、2 つのアプリケーション間における一種の「信用状態」であると考えられます。コンテキストを共有するアプリケーションは誰が相手であるかを知っており、したがって、そのコンテキストが継続する限り、アプリケーション間でデータを転送できます。

  2. 1 つまたは複数の種類の保護 (セキュリティサービス) を転送されるデータに適用します。セキュリティサービスについては、セキュリティサービスを参照してください。

もちろん、GSS-API は上記よりももっと複雑です。GSS-API の他の機能には、データ変換、エラー検査、ユーザー特権の委託、情報の表示および ID の比較などがあります。GSS-API にはさまざまなサポート機能や便利な機能があります。

アプリケーションの移植性

上記のとおり、GSS-API は複数の種類の移植性をアプリケーションに提供します。

セキュリティサービス

GSS-API が提供する基本的なセキュリティは認証です。認証とは ID の検証のことです。あるユーザーが認証されるということは、そのユーザーが自分が宣言したユーザーとして認識されたことを意味します。

実際の機構がサポートする場合、GSS-API は認証以外にも次の 2 種類のセキュリティサービスを提供します。

GSS-API で使用できる機構

GSS-API の現在の実装では、Kerberos v5 セキュリティ機構だけに適用されます。この中には、Sun が変更して作成した Solaris Enterprise Authentication Mechanism (SEAM) も含まれます。詳細は、『Solaris のシステム管理 (セキュリティサービス)』の SEAM に関連する章を参照してください。したがって、GSS-API を使用するプログラムが動作しているシステムには、Kerberos v5 または SEAM がインストールされている必要があります。

RPCSEC_GSS 層

RPC (Remote Procedure Call) プロトコルをネットワークアプリケーションに使用するプログラマは、RPCSEC_GSS を使用してセキュリティを提供できます。RPCSEC_GSS は GSS-API 上にある別の層であり、GSS-API のすべての機能を RPC 向けの方法で提供します。事実、RPCSEC_GSS は GSS-API の多くの側面をプログラマが意識する必要がないようにするため、特に、RPC セキュリティのアクセス性と移植性が向上します。RPCSEC_GSS についての詳細は、『ONC+ 開発ガイド』を参照してください。

図 1–2 RPCSEC_GSS と GSS-API

アプリケーションと GSS-API 層の間に RPCSEC_GSS 層が存在するダイアグラムを表示しています。

GSS-API が行わないこと

GSS-API はデータの保護を簡単にしますが、汎用性という性質を最大限にするために行わない処理があります。その中には、次のことが含まれています。

言語のバインディング

このマニュアルでは現在、GSS-API の C 言語バインディング (関数とデータ型) だけをカバーしています。将来的には、GSS-API の Java バインディングも使用できるようになる予定です。

参照箇所

GSS-API については、次の 2 つのマニュアルでも説明されています。この 2 つの文書はアプリケーション開発者向けというよりも GSS-API 実装者向けです。『Generic Security Service Application Program Interface』 (ftp://ftp.isi.edu/in-notes/rfc2743.txt) は、GSS-API の概念的な概要を示し、『Generic Security Service API Version 2: C-Bindings』 (ftp://ftp.isi.edu/in-notes/rfc2744.txt) は C 言語ベースの GSS-API の特徴について説明します。

基本概念

実際に GSS-API を使用するプロセスを考える前に、4 つの基本的な概念について検証します。用意されているスクリプトは、プリンシパル、GSS-API データ型、状態コード、およびトークンです。

プリンシパル

ネットワークセキュリティの用語では、「プリンシパル」とは、ユーザー、プログラム、またはマシンを指します。プリンシパルはクライアントまたはサーバーのどちらにでもなり得ます。たとえば、 他のマシンにログインしているユーザー (joe@machine)、ネットワークサービス (nfs@machine)、アプリケーションを実行しているマシン (swim2birds@eng.company.com) などがプリンシパルです。

GSS-API では、プリンシパルは特別なデータ型で示されます。名前を参照してください。

GSS-API データ型

次の節では、より重要な表示できる GSS-API データ型について説明します。詳細は、GSS-API データ型と値を参照してください。


注意 – 注意 –

割り当てられたすべてのデータ領域を解放するのは呼び出し元アプリケーションの責任です。


整数

int のサイズはプラットフォームによって異なるため、GSS-API は次の整数型を提供します。


OM_uint32

これは、32 ビットの符号なし整数です。


文字列および類似のデータ

GSS-API はすべてのデータを内部形式で処理するため、文字列は GSS-API 関数に渡す前に GSS-API 形式に変換しておく必要があります。GSS-API は文字列を gss_buffer_desc 構造体で処理します。 gss_buffer_tgss_buffer desc 構造体へのポインタです。



typedef struct gss_buffer_desc_struct {
     size_t     length;
     void       *value;
}  gss_buffer_desc *gss_buffer_t;

したがって、文字列は GSS-API 関数に渡す前に gss_buffer_desc 構造体に変換しておく必要があります。ここでは、メッセージを受け取ってなんらかの方法で処理する (たとえば、転送する前にメッセージに保護を適用するなど)、次のような汎用的な GSS-API 関数を考えます。


例 1–1 文字列の使用例


char *message_string;
gss_buffer_desc input_msg_buffer;

input_msg_buffer.value = message_string;
input_msg_buffer.length = strlen(input_msg_buffer.value) + 1;

gss_generic_function(arg1, &input_msg_buffer, arg2...);

gss_release_buffer(input_msg_buffer);

終了時には gss_release_buffer()input_msg_buffer を解放する必要があることに注意してください。

gss_buffer_desc オブジェクトは文字列だけに使用されるわけではありません。たとえば、トークンも gss_buffer_desc オブジェクトとして処理されます。GSS-API トークンを参照してください。

名前

「名前」はプリンシパルを指します。つまり、joe@companynfs@machinename などのように、人、マシン、またはアプリケーションを指します。GSS-API では、名前は gss_namae_t オブジェクトとして格納され、アプリケーションでは意識する必要はありません。名前は gss_import_name() 関数によって gss_buffer_t オブジェクトから gss_name_t 形式に変換されます。インポートされたすべての名前には関連する「名前型」が割り当てられます。名前型とは、その名前の形式の種類を示すものです。名前型についての詳細は、OIDを参照してください。また、有効な名前型のリストについては、名前型を参照してください。

次に、gss_import_name() の例を示します。


OM_uint32 gss_import_name (
       OM_uint32          *minor_status,
       const gss_buffer_t input_name_buffer,
       const gss_OID      input_name_type,
       gss_name_t         *output_name)

minor_status

実際の機構から戻される状態コード。状態コードを参照してください。

input_name_buffer

インポートされた名前が格納される gss_buffer_desc 構造体。アプリケーションはこの構造体を明示的に割り当てる必要があります。例 1–2、および 文字列および類似のデータを参照してください。使用し終わったとき、この引数は gss_release_buffer() で解放する必要があります。

input_name_type

input_name_buffer の形式を示す gss_OID名前型を参照してください。また、有効な名前型のリストについては、名前型を参照してください。

output_name

名前を受け取る gss_name_t 構造体。

次に、例 1-1 で使用した汎用例を少しだけ変更します。ここでは、どのように gss_import_name() を使用するかを示します。まず、通常の文字列を gss_buffer_desc 構造体に変換して、次に、gss_import_name()gss_name_t 構造体に変換します。


例 1–2 gss_import_name() の使用例


char *name_string;
gss_buffer_desc input_name_buffer;
gss_name_t      output_name_buffer;

input_name_buffer.value = name_string;
input_name_buffer.length = strlen(input_name_buffer.value) + 1;

gss_import_name(&minor_status, input_name_buffer, 
                    GSS_C_NT_HOSTBASED_SERVICE, &output_name);

gss_release_buffer(input_name_buffer);

インポートされた名前を gss_buffer_t オブジェクトに戻して、gss_display_name() で人が読める形式で表示することも可能です。しかし、実際の機構が名前を保存する方法の違いにより、gss_display_name() は結果の文字列がオリジナルと同じであることを保証できません。GSS-API には他にも名前を処理する関数があります。GSS-API 関数 を参照してください。

gss_name_t 構造体は、単一の名前について複数のバージョンを持つことができます。つまり、GSS-API がサポートする機構ごとに 1 つのバージョンが生成されます。たとえば、「joe@company」の gss_name_t 構造体は Kerberos v5 用の名前と他の機構用の名前を持つなどです。GSS-API は gss_canonicalize_name() という関数を提供します。この関数は、内部名 (つまり、gss_name_t 構造体) と機構を入力として受け取り、その機構に特定な名前のバージョンを 1 つだけ持つ別の内部名 (これも gss_name_t 構造体) を出力します。

このような機構に固有な名前のことを「機構名 (Mechanism Name: MN)」と呼びます。機構名は、機構自身の名前を指すのではなく、その機構が生成したプリンシパルの名前を指すため、すこし紛らわしいかもしれません。図 1–3 に、このプロセスを図示します。

図 1–3 内部名と機構名 (MN)

機構名が派生するプロセスを示しています。

名前の比較

なぜこのような関数が便利なのでしょうか。ここでは、サーバーがクライアントから名前を受け取り、その名前をアクセス制御リストから検索する例を考えます。アクセス制御リスト (Access Control List: ACL) とは、特定のアクセス権を備えたプリンシパルのリストのことです。このためには、次のような方法が考えられます。

  1. gss_import_name() で、クライアント名を GSS-API 内部形式でインポートします (まだインポートされていない場合)。

    サーバーの中には、内部形式で名前を受け取るものもあります。この場合、この手順は必要ありません。特に、サーバーがクライアント独自の名前を検索する場合です。コンテキストの起動中、クライアント独自の名前は内部形式で渡されます。

  2. gss_import_name() で、各 ACL 名を インポートします。

  3. gss_compare_name() で、インポートした ACL 名とインポートしたクライアント名をそれぞれ比較します。

図 1–4 に、このプロセスを示します。ここでは手順 1 が必要であると仮定します。

図 1–4 名前の比較 (遅い)

gss_compare_name 関数を使用して、内部クライアント名を比較する方法を示しています。

この手順は、クライアント名と比較する名前の数が少ない場合には有効です。しかし、非常に処理が遅いため、大きなリストを比較するときには不都合です。ACL 名ごとに gss_import_name()gss_compare_name() を実行すると、膨大な CPU サイクルが必要です。したがって、次のような方法を使用します。

  1. gss_import_name() で、クライアント名をインポートします (まだインポートされていない場合)。

    前述の方法と同様に、サーバーが内部形式で名前を受け取る場合、この手順は必要ありません。

  2. gss_canonicalize_name() で、クライアント名の MN を生成します。

  3. gss_export_name() で、「エクスポート名」を生成します。エクスポート名とは、クライアント名の連続する文字列バージョンのことです。

  4. memcmp() で、エクスポートされたクライアント名を ACL 内のすべての名前と比較します。memcmp() は高速で、オーバーヘッドの少ない関数です。

図 1–5 に、このプロセスを示します。ここでも、サーバーがクライアントから名前をインポートする必要があると仮定します。

図 1–5 名前の比較 (速い)

memcmp 関数を使用して、内部クライアント名を比較する方法を示しています。

gss_export_name() は機構名 (MN) を期待するため、あらかじめ、クライアント名に対して gss_canonicalize_name() を実行する必要があります。

詳細は、gss_canonicalize_name(3GSS)gss_export_name(3GSS)、および gss_import_name(3GSS) のマニュアルページを参照してください。

OID

オブジェクト識別子 (Object Identifier: OID) は、次のようなデータを格納するときに使用します。セキュリティ機構、QOP の値 (保護品質の値)、および名前型など。OID は GSS-API の ggss_OID_desc 構造体に格納されます。GSS-API は次のような gss_OID_desc 構造体へのポインタ (gss_OID) を提供します。


例 1–3 OID


typedef struct gss_OID_desc_struct {
        OM_uint32   length;
        void        *elements;
     } gss_OID_desc, *gss_OID;

さらに、gss_OID_set_desc 構造体は1つまたは複数の OID を含むことができます。


例 1–4 OID セット


typedef struct gss_OID_set_desc_struct {
        size_t    count;
        gss_OID   elements;
     } gss_OID_set_desc, *gss_OID_set;


注意 – 注意 –

アプリケーションは free()で OID を解放してはいけません。


機構と保護品質 (QOP)

GSS-API を使用すると、アプリケーションはどの実際のセキュリティ機構を使用するかを選択できます。しかし、アプリケーションは可能な限り、GSS-API が選択したデフォルトの機構を使用するべきです。同様に、GSS-API を使用すると、アプリケーションはどの QOP (保護品質) でデータを保護するかを指定できます。QOP とは、データの暗号化や暗号識別タグの生成に使用されるアルゴリズムのことです。デフォルトの機構を表すには、機構または QOP を期待する関数に値 GSS_C_NULL_OID を引数として渡します。


注意 – 注意 –

セキュリティ機構または QOP を明示的に指定するとアプリケーションの移植性を制限してしまうため、GSS-API を使用する目的が多かれ少なかれ損なわれます。他の実装の GSS-API がその機構または QOP をサポートしなかったり、サポートする方法や範囲が異なる場合があるためです。ただし、付録 C 「OID の指定」 では、使用できる機構と QOP を示して、その選択方法を示しています。


名前型

QOP とセキュリティ機構の他に、OID でも名前型を指定できます。名前型とは、関連する名前の形式を示すものです。たとえば、gss_import_name() 関数はプリンシパルの名前を文字列から gss_name_t 型に変換しますが、この関数は変換すべき文字列の形式を引数の 1 つとして受け取ります。たとえば、名前型が GSS_C_NT_HOSTBASED_SERVICE である場合、gss_import_name() 関数は入力された名前が "service@host" 形式 (たとえば、"nfs@swim2birds") であることが分かります。また、たとえば名前型が GSS_C_NT_EXPORT_NAME である場合、gss_import_name() 関数は入力された名前が GSS-API エクスポート名であることが分かります。アプリケーションは gss_inquire_names_for_mech() 関数を使用すると、指定した機構で使用できる名前型を知ることができます。GSS-API が使用する名前型のリストについては、名前型を参照してください。

状態コード

すべての GSS-API 関数は 2 種類のコードを戻して、関数が成功したか失敗したかについての情報を提供します。どちらの種類の情報コードも OM_uint32 値として戻されます。次に、この 2 種類の戻りコードについて説明します。

GSS-API トークン

GSS-API における流通の基本単位は「トークン」です。GSS-API を使用するアプリケーションはトークンを使用してお互いに通信し、データを交換したり、セキュリティを取り決めたりします。トークンは gss_buffer_t データ型として宣言され、アプリケーションでは意識する必要はありません。

トークンには 2 種類あります。 コンテキストレベルトークンとメッセージ毎トークンです。コンテキストレベルトークンは、主に、コンテキストが確立される (起動され、受け入れられる) ときに使用されます。しかし、その後でコンテキストを管理するためにも使用されます。

メッセージ毎トークンは、コンテキストが確立された後で使用されます。そして、データへの保護サービスを提供します。たとえば、アプリケーションがメッセージを別のアプリケーションに送信したい場合、そのアプリケーションは GSS-API を使用して暗号識別子を生成し、そのメッセージと一緒に送信します。すると、その識別子はトークンに格納されます。

メッセージ毎トークンは「メッセージ」という観点からは次のように考えることができます。「メッセージ」とは、アプリケーションがピアに送信するデータの一部です。たとえば、ls コマンドは ftp サーバーにメッセージを送信します。「メッセージ毎トークン」とは、このようなメッセージに対して GSS-API が生成するもの (暗号化タグやメッセージの暗号化形式など) です。意味論上、最後の例は若干正確ではありません。トークンとは GSS-API が生成した情報にしか過ぎないため、暗号化メッセージはやはりメッセージであり、トークンとは言えません。しかし、正式にではありませんが、「メッセージ」と「メッセージ毎トークン」は同じ意味で使用されることがあります。

次の作業は、GSS-API ではなく、アプリケーションの責任です。

  1. トークンを送受信すること。開発者はこのようなアクションを実行するために、通常、汎用的な読み取り関数と書き込み関数を作成する必要があります。このような関数の例については、send_token()recv_token()を参照してください。

  2. トークンの種類を区別し、種類に従って操作すること。

    トークンはアプリケーションでは意識する必要がないため、アプリケーションにとっては各トークンに違いはありません。アプリケーションはトークンを適切な GSS-API 関数に渡す前に、トークンの内容が分からなくても、トークンを区別できる方法があります。次に、アプリケーションがトークンを区別するための方法を示します。

    • 状態によって (つまり、プログラムの制御フローを通じて)。たとえば、アプリケーションがコンテキストを受け入れるために待機している場合、アプリケーションは、ピアがコンテキストが完全に確立されるまで待機することが判明している、つまり、メッセージ (データ) トークンは送信されないと仮定できるため、受け取るトークンがコンテキスト確立に関連するコンテキストレベルトークンであると仮定できます。コンテキストが確立された後、アプリケーションは受け取るトークンがメッセージトークンであると仮定できます。これは、トークンを処理する最も一般的な方法です。後述のサンプルプログラムでもこの方法を使用しています。

    • トークンを送受信するとき、アプリケーションはトークンの種類を区別できます。たとえば、アプリケーションが独自の関数でピアにトークンを送信する場合、送信するトークンの種類を示すフラグを含めることができます。



      gss_buffer_t token;     /* トークンを宣言 */
      OM_uint32 token_flag       /* トークンの型を記述するフラグ */
      
      <get token from a GSS-API function>
      
      token_flag = MIC_TOKEN;     /* トークンの種類を指定 */
      send_a_token(&token, token_flag);

      受信側のアプリケーションは受信関数 (この例では get_a_token()) で token_flag 引数をチェックします。

    • 3 番目の方法は明示的なタグ付けを行うことです。たとえば、アプリケーションは独自の「メタトークン」を使用できます。メタトークンとはユーザー定義の構造体であり、GSS-API 関数から受け取ったトークンとともに、GSS-API が提供するトークンをどのように使用するかを示すユーザー定義フィールドを格納できます。

プロセス間トークン

GSS-API では、マルチプロセスアプリケーションにおいて、あるプロセスから別のプロセスにセキュリティコンテキストを送信できます。一般的に、マルチプロセスアプリケーションはクライアントのコンテキストを受け入れ、プロセス間で共有します。マルチプロセスアプリケーションについては、コンテキストのエクスポートとインポートを参照してください。

gss_export_context() 関数が作成するプロセス間トークンには、2 番目のプロセスがコンテキストを再構築できるような情報が含まれています。このプロセス間トークンをあるプロセスから別のプロセスに渡すのはアプリケーションの責任であり、また、トークンを別のアプリケーションに渡すのもアプリケーションの責任です。

このプロセス間トークンには、鍵となる、つまり他の重要な情報が格納されることもあります。ところが、必ずしもすべての GSS-API 実装がプロセス間トークンを暗号化で保護するとは保証できません。たとえば、暗号化を使用できる場合は、gss_wrap() でプロセス間トークンを暗号化するなどです。


注 –

異なる GSS-API 実装間では、プロセス間トークンを転送できるとは限りません。


GSS-API を使用するプログラミング

この節では、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 を使用するための基本的な手順を示します。

  1. 各アプリケーション (送信側と受信側) は資格を明示的に獲得します (資格を自動的に獲得していない場合)

  2. 送信側はセキュリティコンテキストを起動し、受信側はそれを受け入れます。

  3. 送信側は転送するメッセージ (データ) にセキュリティ保護を適用します。すなわち、メッセージを暗号化するか、識別タグを付けます。送信側は保護したメッセージを転送します。

    送信側はセキュリティ保護を適用しなくてもかまいません。この場合、関連するデフォルトの GSS-API セキュリティサービスだけがメッセージに適用されます。つまり、認証です。認証を使用すると、受信側は、送信側が本当に受信側の要求したとおりのアプリケーションであるかどうかを知ることができます。

  4. 受信側はメッセージを復号化し (必要であれば)、検証します (該当する場合)。

  5. (省略可能) 確認のため、受信側は識別タグを送信側に返送します。

  6. 送信側と受信側のアプリケーションは両方とも共有セキュリティコンテキストを無効にします。必要であれば、残っている GSS-API データも解放できます。

GSS-API を使用するアプリケーションは gssapi.h ファイルをインクルード(include)します。

図 1–6 に、このプロセスの全体的な概要を示します。この図では、GSS-API が使用できる 1 つの方法しか示していません。しかし、他の場合も考えられます。

図 1–6 GSS-API の使用: 概要

GSS-API がコンテキストを確立し、データを転送する方法を示しています。

資格

「資格」とは、プリンシパル名に対するアプリケーションの要求の証明を提供するデータ構造です。アプリケーションは資格を使用して、ID を確立します。資格はプリンシパルの「識別バッジ」であると考えることもできます。つまり、人、マシン、またはプログラムが本当に要求したとおりのプリンシパルであるかどうか、また多くの場合は、どのような特権を持っているかを証明する情報の集合です。

GSS-API 自身は資格を提供しません。資格は、GSS-API 関数が呼び出される前に、GSS-API の下にあるセキュリティ機構によって作成されます。たとえば、多くの場合、ユーザーはシステムにログインするときに資格を受け取ります。

1 つの GSS-API 資格は単一のプリンシパルだけに有効です。単一の資格は、その単一のプリンシパルに対して複数の (つまり、機構ごとに作成される) 要素を持つことができます。図 1–7 を参照してください。つまり、複数のセキュリティ機構を持つ 1 台のマシン上で獲得された資格は、それらの機構のサブセットだけを持つマシンに転送されるときに有効です。GSS-API は gss_cred_id_t 構造体を通じて資格にアクセスします。この構造体のことを「資格ハンドル」と呼びます。資格はアプリケーションでは意識する必要はありません。ユーザーは、与えられた資格の詳細を知っている必要はありません。

図 1–7 汎用的な GSS-API 資格

GSS-API 資格が 1 つ以上の機構で構成されることを示しています。

資格には 3 つの形式があります。

資格の獲得

セキュリティコンテキストが確立できるようになるまでに、サーバーとクライアントはそれぞれの資格を獲得する必要があります。獲得後、資格は有効期間が満了するまで何度も使用できます。資格が満了したときは、もう一度資格を獲得し直す必要があります。クライアントが使用する資格とサーバーが使用する資格とでは、その有効期間が異なる場合があります。

GSS-API ベースのアプリケーションは、次の 2 つの方法のどちらかで資格を獲得します。

ほとんどの場合、コンテキスト起動側 (クライアント) はログイン時に資格を受け取るため、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)
minor_status

実際の機構が返す状態コード。

desired_name

資格を獲得すべきプリンシパルの名前。上記例では「ftp」です。この引数は gss_import_name() で作成されます (名前を参照)。

desired_nameGSS_C_NO_NAME に設定した場合、汎用の資格が戻されます。つまり、GSS-API のコンテキスト起動ルーチンとコンテキスト受け入れルーチンは資格に関してデフォルトの動作を使用します。言い換えると、gss_acquire_cred()GSS_C_NO_NAME を渡すと、gss_init_sec_context() または gss_accept_sec_context() にデフォルトの資格要求 (GSS_C_NO_CREDENTIAL) を渡したときと同じ資格が戻ります。詳細は コンテキストの起動 (クライアント)コンテキストの受け入れ (サーバー) を参照してください。

time_req

資格が有効であるべき時間 (秒)。GSS_C_INDEFINITE を指定すると、最大の可能な有効期間を要求することができます。

desired_mechs

アプリケーションがこの資格で使用したい実際の機構の集合。これは gss_OID_set データ構造体であり、それぞれが適切な機構を表す 1 つまたは複数の gss_OID 構造体を持ちます。可能な限り、GSS_C_NO_OID_SET を指定して、GSS-API からデフォルトのセットを取得してください。

cred_usage

この資格をどのように使用するかを示すフラグ。コンテキストを起動する場合は GSS_C_INITIATE、コンテキストを受け入れる場合は GSS_C_ACCEPT、または両方の場合は GSS_C_BOTH に設定します。

output_cred_handle

この関数から戻される資格ハンドル。

actual_mechs

この資格で使用できる機構のセット。どの機構であるかを知る必要がない場合は、NULL に設定します。

time_rec

資格が実際に有効である時間 (秒)。時間が重要でない場合は、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() を呼び出す前に、クライアントは次のことを行う必要があります。

  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–5 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–6 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_flagsGSS_C_DELEG_FLAG が含まれている場合だけ有効です。委託についての詳細は、委託を参照してください。

正常に終了した場合、gss_accept_sec_context()GSS_S_COMPLETE を戻します。コンテキストが完全に確立されていない場合、gss_accept_sec_context()GSS_S_CONTINUE_NEEDED を戻します。エラーコードについては、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 資格の委託

中間サーバーをプロクシとして使用して、次のサーバーへ安全にアクセスする方法を示しています。

委託が許可されると、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 リプレイされたメッセージと順序が正しくないメッセージ

メッセージが重複している、または順序が正しくない、エラー状態を示しています。

このような 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–7 を参照してください。


例 1–7 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 コンテキストのエクスポート: マルチスレッド化された受け入れ側の例

マルチプロセスの受け入れ側が、コンテキストレベルトークンとデータトークンを分割し、次のプロセスへ各トークンを渡す方法を示しています。

コンテキスト情報

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

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

データ保護

ピア間 (つまり、クライアントとサーバー間) でコンテキストが確立された後、メッセージは送信する前に保護できます。

コンテキストを確立しメッセージを送信するだけの場合、最も基本的な GSS-API 保護である「認証」が使用されます。 認証を使用すると、受信側は、送信側であるべきと要求されているプリンシパルからのメッセージであるかどうかを知ることができます。使用される実際のセキュリティ機構によって異なりますが、GSS-API は次の 2 つの保護も提供します。

図 1–11 に、2 つの関数の違いを示します。

図 1–11 gss_get_mic()gss_wrap()

gss_get_mic 関数と gss_wrap 関数の違いを示しています。

どちらの関数を使用するかは、ユーザーの必要性によって異なります。gss_wrap() は整合性サービスも含むため、多くのプログラムは gss_wrap() を使用します。機密性サービスを使用できるかどうかをテストするには、機密性サービスを付けて (または、付けずに) gss_wrap() を呼び出します。使用例は、データの送信(プログラムリストは call_server()) を参照してください。しかし、gss_get_mic() で保護されたメッセージは受信側がラップ解除する必要がないため、gss_wrap() を使用するときよりも CPU サイクルを節約できます。したがって、機密性が必要ないプログラムは gss_get_mic() でメッセージを保護する傾向にあります。

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)

minor_status

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

context_handle

メッセージが送信されるコンテキスト。

qop_req

要求する QOP (保護品質)。MIC を生成するときに使用される暗号化アルゴリズムです。移植性のためには、アプリケーションは可能な限りデフォルトの QOP を指定するべきです。つまり、この引数に GSS_C_QOP_DEFAULT を設定します。デフォルト以外の QOP の指定については、付録 C 「OID の指定」 を参照してください。

message_buffer

MIC をタグ付けするメッセージ。この引数は gss_buffer_desc オブジェクトの形式である必要があります 。文字列および類似のデータを参照してください。アプリケーションが使用し終わったときには、gss_release_buffer() で解放する必要があります。

msg_token

メッセージと MIC が入っているトークン。使用し終わったときには、gss_release_buffer() で解放する必要があります。

gss_get_mic() はメッセージと MIC を別々に出力します。これは、gss_wrap() とは異なります。gss_wrap() は両方を一緒にして出力します。さらに重要なことは、受信側アプリケーションがメッセージと MIC を受信および区別できる必要があるということです。メッセージと MIC を適切に処理するには、次のような方法があります。

正常に終了した場合、gss_get_mic()GSS_S_COMPLETE を戻します。指定した QOP が有効でなかった場合、gss_get_mic()GSS_S_BAD_QOP を戻します。詳細は、gss_get_mic(3GSS) のマニュアルページを参照してください。

gss_wrap() によるメッセージのラップ

メッセージは gss_wrap() 関数で「ラップ」することも可能です。gss_get_mic() と同様に、gss_wrap() は MIC を提供します。機密性が要求される場合 (かつ、実際の機構で使用できる場合)、gss_wrap() はさらにメッセージを暗号化します。メッセージの受信側は gss_unwrap() でメッセージを「ラップ解除」します。次に、gss_unwrap() の形式を示します。



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 )

minor_status

実際のセキュリティ機構から戻される状態コード。

context_handle

このメッセージが送信されるコンテキスト。

conf_req_flag

機密性サービス (暗号化) を要求するためのフラグ。0 以外の場合、機密性と整合性の両方を要求します。0 の場合、整合性サービスだけを要求します。

qop_req

要求する QOP (保護品質)。MIC を生成するときと暗号化を行うときに使用される暗号化アルゴリズムです。移植性のためには、アプリケーションは可能な限りデフォルトの QOP を指定するべきです。つまり、この引数に GSS_C_QOP_DEFAULT を設定します。デフォルト以外の QOP の指定については、付録 C 「OID の指定」 を参照してください。

input_message_buffer

ラップするメッセージ。この引数は gss_buffer_desc オブジェクトの形式である必要があります。文字列および類似のデータを参照してください。アプリケーションが使用し終わったときには、gss_release_buffer() で解放する必要があります。

conf_state

関数が戻ったときに、機密性が適用されたかどうかを示すフラグ。0 以外の場合、機密性、メッセージ起点認証、および整合性サービスが適用されたことを示します。0 の場合、メッセージ起点認証と整合性だけが適用されたことを示します。必要ない場合は、NULL を指定します。

output_message_buffer

ラップしたメッセージ用のバッファ。アプリケーションがメッセージを処理した後には、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 つの影響を受けます。

次に、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)

minor_status

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

context_handle

データが転送されるコンテキスト。

conf_req_flag

機密性サービス (暗号化) を要求するためのフラグ。0 以外の場合、機密性と整合性の両方を要求します。0 の場合、整合性サービスだけを要求します。

qop_req

要求する QOP (保護品質)。MIC を生成するときと暗号化を行うときに使用される暗号化アルゴリズムです。移植性のためには、アプリケーションは可能な限りデフォルトの QOP を指定するべきです。つまり、この引数に GSS_C_QOP_DEFAULT を設定します。デフォルト以外の QOP の指定については、付録 C 「OID の指定」 を参照してください。

req_output_size

指定した転送プロトコルが処理できるデータ片の最大サイズ (型は int)。この情報は、ユーザーが自ら提供する必要があります。つまり、GSS-API はプロトコルに依存しないため、どのプロトコルが使用されるのかを知る方法がありません。

max_input_size

関数から戻される値。つまり、ラップしたときに 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()

次に、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)

minor_status

実際のセキュリティ機構から戻される状態コード。

context_handle

このメッセージが送信されるコンテキスト。

input_message_buffer

ラップされたメッセージ。この引数は gss_buffer_desc オブジェクトの形式である必要があります。文字列および類似のデータを参照してください。アプリケーションが使用し終わったときには、gss_release_buffer() で解放する必要があります。

output_message_buffer

ラップ解除したメッセージ用のバッファ。アプリケーションがラップ解除したメッセージを処理した後には、gss_release_buffer() でこのバッファを解放する必要があります。この引数も gss_buffer_desc オブジェクトです。

conf_state

機密性が適用されたかどうかを示すフラグ。0 以外の場合、機密性、メッセージ起点認証、および整合性サービスが適用されたことを示します。0 の場合、メッセージ起点認証と整合性だけが適用されたことを示します。必要ない場合は、NULL を指定します。

qop_state

使用する QOP (保護品質)。MIC を生成するときと暗号化を行うときに使用される暗号化アルゴリズムです。必要ない場合は、NULL を指定します。

メッセージが正常にラップ解除された場合、gss_unwrap()GSS_S_COMPLETE を戻します。MIC に対してメッセージを検証できなかった場合、gss_verify_mic()GSS_S_BAD_SIG を戻します。

gss_verify_mic()

メッセージがラップ解除された場合、あるいは、初めからメッセージがラップされていない場合は、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)

minor_status

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

context_handle

メッセージが送信されるコンテキスト。

message_buffer

受信したメッセージ。この引数は gss_buffer_desc オブジェクトの形式である必要があります。 文字列および類似のデータを参照してください。アプリケーションが使用し終わったときには、gss_release_buffer() で解放する必要があります。

token_buffer

受信した MIC が入っているトークン。この引数は gss_buffer_desc オブジェクトの形式である必要があります。文字列および類似のデータを参照してください。アプリケーションが使用し終わったときには、gss_release_buffer() で解放する必要があります。

qop_state

MIC を生成するときに適用される QOP (保護品質)。必要ない場合は、NULL を指定します。

メッセージが正常に検証された場合、gss_verify_mic()GSS_S_COMPLETE を戻します。MIC に対してメッセージを検証できなかった場合、gss_verify_mic()GSS_S_BAD_SIG を戻します。

転送の確認 (任意)

転送されたメッセージをラップ解除または検証した後、受信側は送信側に確認を送信することもできます。つまり、そのメッセージの MIC を返送します。送信側がラップはしなかったが gss_get_mic() で MIC をタグ付けしているメッセージの場合を考えます。図 1–14 に、このプロセスの様子を示します。

  1. 起動側は gss_get_mic() でメッセージにタグ付けします。

  2. 起動側はメッセージと MIC を受け入れ側に送信します。

  3. 受け入れ側は gss_verify_mic() でメッセージを検証します。

  4. 受け入れ側は MIC を起動側に返送します。

  5. 起動側は gss_verify_mic() で、オリジナルのメッセージに対して受信した MIC を検証します。

図 1–14 MIC 付きデータの確認

MIC 付きデータの確認方法を示しています。

ラップされたデータの場合、gss_unwrap() 関数はメッセージと MIC を別々に生成しません。したがって、受信側は、受信した (およびラップ解除した) メッセージから MIC を生成する必要があります。図 1–15 に、このプロセスの様子を示します。

  1. 起動側は gss_wrap() でメッセージをラップします。

  2. 起動側はラップしたメッセージを送信します。

  3. 受け入れ側は gss_unwrap() でメッセージをラップ解除します。

  4. 受け入れ側は gss_get_mic() でラップ解除されたメッセージの MIC を生成します。

  5. 受け入れ側は抽出した MIC を起動側に返信します。

  6. 起動側は gss_verify_mic() で、オリジナルのメッセージに対して受信した MIC を検証します。

図 1–15 ラップされたデータの確認

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)

minor_status

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

context_handle

削除されるコンテキスト。

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() があります。詳細は、それぞれのマニュアルページを参照してください。