C    GSS-API チュートリアル

この付録では,GSS-API を使用してアプリケーションをセキュアにする方法を,C 言語によるサンプル・コードを用いて説明します。Application Security SDK に含まれているサンプル・プログラムについても説明します。次の内容について説明しています。

C.1    セキュリティの基礎

Kerberos を使ったネットワーク認証に慣れていない方は,まずこの章をお読みください。 ここでは以下の内容を取り上げます。

C.1.1    基本概念

最初に次の基本概念について説明します。

C.1.2    Kerberos セキュリティ・モデル

Kerberos は,マサチューセッツ工科大学で開発された,双方向の第三者による認証および鍵配布システムです。

C.1.2.1    定義

クライアント -- ユーザに代わってネットワーク・サービスを利用するプログラムまたはプロセス。場合によっては,サーバ自身が他のサーバのクライアントになることがあります (たとえば,プリント・サーバは,ファイル・サーバのクライアントです)。

ユーザ -- クライアント・プログラムを使う人。

アプリケーション・サーバおよびサービス -- 分散型アプリケーションの一方からのサービスを提供するホスト・システム。 ユーザはクライアント・プログラムを実行して,アプリケーション・サーバ上で実行しているサービスにアクセスします。

プリンシパル -- HP のセキュリティ・システムを使ってエンティティを識別する手段。つまり,セキュリティ・サーバを使って秘密鍵を保存したユーザ,クライアント,サービス,アプリケーション,ホスト・システムなど。

Key Distribution Center (KDC) -- プリンシパル・データベース,認証サーバ,チケット・グランティング・サービスを保持するセキュリティ・サーバ。これらの KDC コンポーネントは,プリンシパルに信任状を提供し,プリンシパルはこの信任状によって本人であることを証明し,メッセージを交換できるようになります。

プリンシパル・データベース -- Kerberos 認証で使われる共有の秘密 (つまり秘密鍵) を保持するデータベース (通常は KDC と同じマシンに置かれます)。各ユーザはこのデータベースにプリンシパルを持っています。

レルム -- 1 つ以上の KDC によってサービスが提供されているネットワーク上の,一連のプリンシパルを表す名前。1 つのレルム内のプリンシパル名はすべて,一意でなければなりません。1 つのレルム内では,管理ポリシはすべてのプリンシパルに対して同じになります。

サービス -- サーバ上で実行し,ネットワーク上のクライアントから利用可能なアプリケーション。

-- 暗号化と復号の処理の中で使われる,パスワードなどの秘密鍵。

チケット -- あるプリンシパルを別のプリンシパルに対して認証するための信任状。KDC だけが,Kerberos チケットを発行できます。

C.1.2.2    概念と処理手順

以降の節では,Kerberos の概念と処理手順について説明します。

C.1.2.2.1    共有秘密

相互に安全なやり取りを望んでいる 2 つのプリンシパルは,まず,秘密鍵を共有する必要があります。 セッション鍵と呼ばれるこの秘密鍵は,ランダムに生成され,やり取りをしようとしている 2 つのプリンシパルだけに与えられます。セッション鍵は,認証と暗号化のために両方のプリンシパルによって使われます。

C.1.2.2.2    信用できる第三者による調停

各プリンシパルは秘密鍵を持っています。秘密鍵は,プリンシパルが変更しない限り,変更されることはありません。一方セッション鍵はランダムに生成され,1 回のセッションで 2 つのプリンシパル間で必要な間だけ存在します。

サービスはクライアントを信用せず,クライアントもまたサービスを信用しません。クライアントとサービスは,セッション鍵の生成と配布を行う Key Distribution Center だけを信用します。

C.1.2.2.3    Kerberos ネットワーク

Kerberos ネットワークは,レルムと呼ばれるセキュリティ・ドメインに分かれています。 各レルムは専用の認証サーバ (KDC) を持っており,専用のセキュリティ・ポリシを実装しています。これにより Kerberos を実装する組織は,組織内の情報の種類に応じてさまざまなレベルのセキュリティを持つことができます。

レルムは他のレルムからの認証を受け入れることができます。あるいは情報セキュリティ・ポリシが再認証を要求する場合は,再認証なしでは受け入れないこともできます。これはレルム間認証と呼ばれます。

レルムは階層構造です。つまり,各レルムは子レルムを持つことや,親レルムを持つことがあります。このような構造により,直接的なやり取りのないレルム同士が認証情報を共有できるようになっています。

C.1.2.2.4    認証までの 3 つの段階

Kerberos の認証処理には,次の 3 つの段階があります。

  1. 初回信任状 クライアントが,パスワードを使って,他のサービスへのアクセス要求の中で使う初回信任状 (チケット・グランティング・チケット,TGT) を取得する。

    初回信任状を取得するときに,クライアントと KDC は,認証サービス・メッセージを交換します。

  2. クライアントが特定のサービスに対する認証を要求する。

    サービス・チケットを取得したら,クライアントと KDC が,チケット・グランティング・サービス・メッセージを交換します。

  3. クライアントが,サービスに対してサービス・チケットを提示する。

    これを行うために,クライアントと要求されたサービスがアプリケーション・メッセージを交換します。

C.1.2.2.5    認証サービス・メッセージの交換

認証サービス(Authentication Service,AS) の交換では,チケット・グランティング・サービス (Ticket-Granting Service, TGS) で使う初回信任状とセッション鍵 (共有秘密) がクライアントに提供されます。 これらの信任状チケット・グランティング・サービスに提示して,クライアントが本人であることを特定のサービスに対して証明する信任状 (つまり,サービス・チケット) を要求できます。

このメッセージ交換は,クライアントによって生成された要求と,KDC 認証サービスによって生成された応答からなります。この交換の最後に,クライアントはチケット・グランティング・サービスに対して自分自身を認証できる初回信任状 (チケット・グランティング・チケット) を取得します。

認証サービスは,クライアントから要求メッセージを受け取るときに,そのクライアントを認識しているかどうかをチェックします。認識していれば,ランダムなセッション鍵 (これがクライアントとチケット・グランティング・サービスの間の共有秘密になります) と TGT (クライアントが,チケット・グランティング・サービスに対して自身を認証するために使われます) を生成します。

認証サービスは,応答メッセージの一部として,セッション鍵と TGT の両方を送信します。認証サービスにはクライアントが認証されたものかどうかがわからないため,クライアントの秘密鍵を使って応答メッセージの一部を暗号化します。認証されているクライアントだけがこの部分を復号できるとわかっているからです。

C.1.2.2.6    チケット・グランティング・サービス・メッセージの交換

1 つのチケットは,1 回のサービスに対してのみ有効です。これには,チケット・グランティング・サービスのサービスを使うためのチケットである TGT も含まれます。このため,クライアントが使いたいサービスごとに,異なるサービス・チケットを取得する必要があります。クライアントは,KDC のチケット・グランティング・サービスにメッセージを送ることによって,チケット・グランティング・サービスからサービス・チケットを取得します。本人であることを証明するために TGT 使われるため,ここではユーザ名とパスワードのプロンプトは必要ありません。

クライアントは,(TGT も含む) チケットをサービスに提示するときに認証子も提示します。 認証子には,チケットのセッション鍵を使って暗号化されたクライアント名が格納されています。このような方法で,サービスがチケットのセッション鍵を使って認証子を復号でき,クライアントの名前がチケット内の名前と一致していれば,クライアントは認証されたことを保証できます。サービスはクライアントがセッション鍵を知っていると認定し,承認されていない信任状のリプレイを検出する手助けをします。認証子は 1 回のみ使用できます。

チケット要求メッセージを受け取った後,チケット・グランティング・サービスは TGT を復号します。その後,認証子を復号するためにセッション鍵が使われます。クライアント名が認証子と TGT の両方で一致すると,クライアントは,チケット・グランティング・サービスに対して自身を認証することに成功し,サービス・チケットが付与されます。

サービス・チケットは,サービスの秘密鍵を使って暗号化された応答メッセージに入れられて,クライアントに送信されます。メッセージのうち暗号化された部分は,クライアントの秘密鍵ではなく TGT セッション鍵を使って暗号化されています。このため,ユーザはパスワードをもう一度入力する必要はありません。

応答メッセージを受け取った後,クライアントは暗号化された部分を復号します。その後,クライアントはサービス・チケットとそれに対応するセッション鍵を,信任状キャッシュに格納します。

C.1.2.2.7    アプリケーション間のメッセージの交換

クライアントは,サービスに対するサービス・チケットを取得した後,サービスに対して自身を認証し,サービスとの間で安全にメッセージを交換できるようになります。クライアントは,サービス・チケットを認証子と共に検証のためにサービスに送信します。

C.1.2.3    信任状の属性

クライアントは,KDC によって発行された信任状に次のような特徴を付加することを要求できます。

C.2    はじめに

Application Security SDK を使って分散型アプリケーションを保護する前に,考えなければならない最初の決定事項は,次のとおりです。

  1. このアプリケーションを開始する前に,アプリケーション・ユーザ用の初回信任状 (TGT) は用意されているか。

    用意しないのであれば,アプリケーションは csf_gss_acq_user() を呼び出すことによってユーザ・コンテキストを確立する必要があります。この関数は,アプリケーション・ユーザのために,初回信任状 (TGT) をセキュリティ・サーバから取得します。これらの信任状は,以降の処理の間,開始側のアプリケーションによって使われます。本書ではこれらを,しばしば「開始側の信任状」と呼びます。

    DES3 暗号化または公開鍵の信任状が使われている場合,アプリケーションはこれらの属性を csf_gss_acq_user() に渡す必要があります。

  2. アプリケーションには相互認証が必要か。

    相互認証は,開始側のアプリケーションが,受け入れ側のアプリケーションの識別情報を検証する必要があるときに推奨されます。たとえば受け入れ側のアプリケーションにクレジット・カード番号などの機密性の高いデータを送信する場合などです。

    相互認証が必要であれば,開始側のアプリケーションは,gss_init_sec_context() を呼び出して,コンテキスト確立時に相互認証を要求する必要があります。

  3. (もしあれば) どのメッセージをアプリケーションとそのやり取り相手の間で保護する必要があるか。

    中には,アプリケーションが必要としているサービスが,認証だけの場合もあります。

  4. メッセージを保護する必要がある場合は,どの種類の保護が必要か。

    保護のタイプは,機密性と完全性という 2 つの基本的なカテゴリに分類されます。

  5. メッセージの保護のためにどのような Quality of Protection (QOP) が必要か。

    最も低いレベル (DES 暗号化) は,高速ですが安全性は低くなります。最も高いレベル (DES3 暗号化) は,時間がかかりますが安全性は高くなります。アプリケーションが DES3 暗号化を使用する場合は,いくつかの前提条件を満たす必要があります。

C.3    基本的な GSS-API 関数の使用

GSS-API においては,セキュリティ・コンテキストは開始される受け入れられるかのどちらかになります。アプリケーションの役割によって,それがセキュリティ・コンテキストを開始するのか,受け入れるのかが決まります。クライアント/サーバ・アプリケーションでは,通常はクライアントはセキュリティ・コンテキストを開始し,サーバはセキュリティ・コンテキストを受け入れます。サーバが別のセキュア・サービスのクライアントになることもあります。

GSS-API 関数を使って開始側と受け入れ側の間でセキュリティを実装する手順は,大きく分けて次の 5 つからなります。

  1. 名前の取得

  2. 信任状の取得

  3. セキュリティ・コンテキストの確立

  4. メッセージの交換

  5. セキュリティ・コンテキストの終了

開始側と受け入れ側の両方のアプリケーションが,この手順を同じ順番で実行する必要があります。ただし,すべての手順が必須というわけではありません。たとえば,信任状の取得は,省略時の信任状を使う場合は省略できます。

両方のアプリケーションが,下に示す順番でこれらの手順を実行する必要があります。たとえば,アプリケーション間でコンテキストを確立するには,アプリケーションの双方が信任状を取得しなければなりません。

ここで取り上げる基本的な GSS 関数の説明では,開始側のアプリケーション (開始側) はユーザ, 受け入れ側のアプリケーション (受け入れ側) はサービスであると仮定します。

以降の説明では,両方のアプリケーションはすでに,セキュリティ・サーバから初回信任状 (つまり TGT),または秘密鍵を取得しているものとします。実行時に初回信任状を取得する場合は,HP の GSS-API 拡張である csf_gss_acq_user() を使ってユーザ・コンテキストを確立する必要があります。

以降の節の各手順で説明されている関数は,使用可能な GSS-API 関数のサブセットです。これらは,Application Security SDK でアプリケーションを保護するために最低限必要な呼び出しです。

C.4    手順 1: 名前の取得

アプリケーションを保護するためには,この処理にかかわる対象の名前を取得する必要があります。この手順では,開始側のユーザ名と,受け入れ側のサービス名をインポートする方法を説明します。これらの名前は,信任状の取得とセキュリティ・コンテキストの確立に使われます。

gss_import_name() 関数を使って,名前を他の GSS-API 関数が使用できるような内部形式に変換します。 さまざまな形式,つまり名前タイプを変換のタイプとして指定できます。

内部形式による名前は,表示しても判別できませんが, gss_display_name() を使って人間が判読できる形式に変換できます。この関数は,省略時の信任状を取得した場合に,既存の信任状に対応するプリンシパルを表示するのに便利です。

開始側と受け入れ側のどちらかがプリンシパル名 (ユーザ名またはサービス名) をインポートし,表示するときに,同じ処理が発生します。「GSS-API 名前管理関数」で,他の名前関数を使って実行できることについて説明されています。

注意

開始側からの gss_import_name() の呼び出しは省略可能です。gss_import_name() が開始側によって呼び出されなければ,省略時の信任状が要求された場合,gss_acquire_cred() または gss_init_sec_context() が呼び出されるときに,省略時のプリンシパル名が信任状キャッシュから取り出されます。ただし,gss_init_sec_context() の呼び出しによって受け入れ側の名前が要求されるため,開始側でその名前をインポートする必要があります。

受け入れ側からの gss_import_name() の呼び出しもまた省略可能です。gss_import_name() が開始側によって呼び出されなければ, 省略時のサービス・プリンシパル名 (host/hostname@REALM) が,gss_acquire_cred() または gss_accept_sec_context() の呼び出し時に作成されます。

gss_import_name() 関数には次のパラメータがあります。

入力パラメータ  
input_name_buffer 変換するテキスト名。
input_name_type 名前のタイプ -- 公開鍵,Kerberos,汎用名タイプがサポートされています。
出力パラメータ  
minor_status Kerberos 5 エラー・コード。
output_name 内部形式による名前が戻されます。

サンプル・プログラムから抜粋した下記のコードは,開始側の名前をインポートして,人間が判読可能な形式に変換する方法を示しています。 名前タイプには,Kerberos 5 の省略時の値,つまりここでは GSS_C_NT_USER_NAME が指定されています。これはユーザ・プリンシパルに対してよく使われる名前タイプです。この名前タイプは,ユーザ名 user をuser@LOCAL_REALM という形式に変換します。

/***************************************************************/
 
char            szUserName[]      = "walth@APPSEC.CYBERSAFE.COM";
OM_uint32       gMaj, gMin        = 0;
gss_buffer_desc input_name        = GSS_C_EMPTY_BUFFER;
gss_buffer_desc display_name      = GSS_C_EMPTY_BUFFER;
gss_name_t      principal_name    = GSS_C_NO_NAME;
gss_OID         display_name_type = GSS_C_NO_OID;
 
/* Copy the principal name into the GSS buffer structure */
input_name.length = strlen( szUserName );
input_name.value  = strdup( szUserName );
 
/* Convert the user principal name into GSS internal form */
gMaj = gss_import_name( &gMin,
                        &input_name,
                        GSS_C_NT_USER_NAME,
                        &principal_name );
 
/* Convert the imported name to human-readable form */
gMaj = gss_display_name( &gMin,
                         principal_name,
                         &display_name,
                         &display_name_type );
 
/***************************************************************/

サンプル・プログラムから抜粋した下記のコードは,受け入れ側の名前をインポートして,人間が判読可能な形式に変換する方法を示しています。名前タイプには,Kerberos 5 の省略時の値,つまりここでは GSS_KRB5_NT_HOSTBASED_SERVICE_NAME が指定されています。これは無人運用ホストに対してよく使われる名前タイプです。 この名前タイプは,Kerberos のホスト・サービス・プリンシパル service@hostservice/fqdn@REALM の形式に変換します。たとえば,ftp@fujiftp/fuji.company.com@COMPANY.COM に変換されます。

/***************************************************************/
 
char            szHostName[]      = "host@dev007.cybersafe.com";
OM_uint32       gMaj, gMin        = 0;
gss_buffer_desc input_name        = GSS_C_EMPTY_BUFFER;
gss_buffer_desc display_name      = GSS_C_EMPTY_BUFFER;
gss_name_t      principal_name    = GSS_C_NO_NAME;
gss_OID         display_name_type = GSS_C_NO_OID;
 
/* Copy the host service principal name
   into the GSS buffer structure */
input_name.length = strlen( szHostName );
input_name.value  = strdup( szHostName );
 
/* Convert the host service principal name
   into GSS internal form */
gMaj = gss_import_name( &gMin,
                        &input_name, 
                        GSS_KRB5_NT_HOSTBASED_SERVICE_NAME,
                        &principal_name );
 
/* Convert the imported name to human-readable form */
gMaj = gss_display_name( &gMin,
                         principal_name,
                         &display_name,
                         &display_name_type );
 
/***************************************************************/

C.5    手順 2: 信任状の取得

ここでは,開始側と受け入れ側の信任状の取得方法を説明します。信任状には,開始側と受け入れ側が相互に認証するために使う,セキュリティ・サーバからの TGT とサービス鍵テーブル・エントリが含まれています。このため,開始側と受け入れ側の両方が,セキュリティ・コンテキストを確立する前に信任状を取得する必要があります。

要求される信任状のタイプには,次の 3 つがあります。

以下に示すように,信任状の取得はローカルな処理です。ピア・アプリケーションとの通信は必要ありません。

gss_acquire_cred() 関数は,インポートされた名前を使って,ユーザまたはサービス名に対応する有効なチケットを探します。信任状は,開始側の場合は HP の信任状キャッシュの中に,受け入れ側の場合はサービス鍵テーブルの中に存在していなければなりません。ただし,受け入れ側アプリケーションが,他の受け入れ側アプリケーションとのセキュリティ・コンテキストの開始も行う場合は例外です。たとえば,プロキシがその例です。この場合,信任状キャッシュとサービス鍵テーブル・ファイル・エントリの両方がどちらかの役割をサポートする必要があります。

サービス鍵テーブル・ファイルの省略時の名前は,Windows と UNIX のどちらのプラットフォームでも v5srvtab です。

gss_acquire_cred() GSS_C_INITIATE 信任状を要求する開始側によって呼び出されると,この関数は渡されたプリンシパル名を調べ,信任状キャッシュの中で対応する TGT を探します。 プリンシパル名の指定がない場合,この関数は,信任状キャッシュの省略時のプリンシパル名と同じ省略時の名前を使って,信任状キャッシュから有効な TGT を探します (ユーザのログイン名は使用されません)。

gss_acquire_cred() GSS_C_ACCEPT 信任状を要求する受け入れ側によって呼び出されると,この関数は渡されたプリンシパル名を調べ,サービス鍵テーブル・ファイルの中で対応するエントリを探します。プリンシパル名の指定がない場合,この関数は,host/fqdn@REALM の省略時の受け入れ側のプリンシパル名に対応する,サービス鍵テーブル・ファイル・エントリを探します。

セキュリティ・コンテキストの開始側にも受け入れ側にもなるアプリケーションは,信任状キャッシュとサービス鍵テーブルの両方を保持している必要があります。この場合,gss_acquire_cred() は,GSS_C_INITIATE 信任状を要求するアプリケーションによって呼び出されると,プリンシパル名が渡されたことを確認し,このプリンシパル名に対応する有効なTGT が信任状キャッシュにあるかどうか探します。信任状キャッシュに TGT がなければ,この関数はサービス鍵テーブルで該当するエントリを探します。サービス鍵テーブルにエントリがない場合は,テーブル・ファイルの鍵を使って KDC から TGT を取得します。

注意

開始側からの gss_acquire_cred() の呼び出しは省略可能です。gss_init_sec_context() が呼び出されるまで開始側が gss_acquire_cred() を呼び出さない場合,名前が省略時のものでタイプが GSS_C_INITIATE である信任状が取得されます。

受け入れ側からの gss_acquire_cred() の呼び出しもまた省略可能です。この場合,gss_accept_sec_context() は,名前が省略時のものでタイプが GSS_C_ACCEPT である信任状を取得します。受け入れ側アプリケーションが gss_acquire_cred() で信任状を取得し,必要に応じてこれを再利用すると,性能の向上につながります。

gss_acquire_cred() では次のパラメータを使用します。

入力パラメータ  
desired_name 信任状を要求しているプリンシパルまたはサービスの名前。指定されなければ,省略時のプリンシパルが使用されます。
time_req 要求された信任状の存続期間 (無視されます)。信任状はすでに存在しているので,信任状の存続期間は指定できません。存続期間は,信任状が作成された状況によって決まります。
desired_mechs 要求されているセキュリティ・メカニズム (Kerberos 5)。
cred_usage 信任状の用途 (開始,受け入れ,または両方)。
出力パラメータ  
minor_status Kerberos 5 エラー・コード。
output_cred_handle 取得した信任状。
actual_mechs 使用されているセキュリティ・メカニズム (Kerberos 5)。
time_rec 信任状の存続期間が戻されます。これは,開始側でのみサポートされています。受け入れ側の存続期間は不定です。

サンプル・プログラムから抜粋した下記のコードは,開始側用に GSS_C_INITIATE 信任状を,受け入れ側用に GSS_C_ACCEPT 信任状を取得する方法を示しています。プリンシパル名は手順 1 でインポートされています。

/****************************************************************\
 
 
OM_uint32     gMaj, gMin              = 0;
OM_uint32     cred_lifetime_requested = 600;
OM_uint32     cred_lifetime_received  = 0;
i_32          cred_usage              = GSS_C_INITIATE;
gss_cred_id_t cred_handle             = GSS_C_NO_CREDENTIAL;
gss_OID_set   actual_mechs            = GSS_C_NO_OID_SET;
 
/* Get an Initiator credential from the cred cache */
gMaj = gss_acquire_cred( &gMin,
                         principal_name,
                         cred_lifetime_requested,
                         rfc_krb5_c_OID_set,
                         cred_usage,
                         &cred_handle,
                         &actual_mechs,
                         &cred_lifetime_received );
     :
     :
     :
 
OM_uint32     gMaj, gMin             = 0;
OM_uint32     cred_lifetime_received = 0;
i_32          cred_usage             = GSS_C_ACCEPT;
gss_cred_id_t cred_handle            = GSS_C_NO_CREDENTIAL;
gss_OID_set   actual_mechs           = GSS_C_NO_OID_SET;
 
/* Get an Acceptor credential from the cred cache
   or from the v5srvtab key table file */
gMaj = gss_acquire_cred( &gMin,
                         principal_name,
                         GSS_C_INDEFINITE,
                         GSS_C_NO_OID_SET,
                         cred_usage,
                         &cred_handle,
                         &actual_mechs,
                         &cred_lifetime_received );
 
/****************************************************************\

信任状を取得した後は,gss_release_cred() 関数を使って,割り当てられていた記憶域を解放する必要があります。サンプル・プログラムにこの例が含まれています。

一般に,バッファがユーザによって (mallocstrdup などを使って) ローカルに割り当てられた場合は,アプリケーションがこれを解放する必要があります。バッファが GSS-API 関数によって割り当てられた場合は,gss_release_xxx() 関数を使って解放する必要があります。これらのアクションはメモリ・リークを防ぎます。

「信任状管理関数」で,他の信任状関数を使ってできる操作について示してあります。

C.6    手順 3: セキュリティ・コンテキストの確立

アプリケーションとそのピアが信任状を取得した後,セキュリティ・コンテキストを確立できます。 セキュリティ・コンテキストとは基本的に,アプリケーションとそのピアとの間の対話を保護する,一連のセキュリティ・パラメータです。

アプリケーションとそのピアの間に,複数のセキュリティ・コンテキストが同時に存在することがあります。ただし,1 つのコンテキストを,複数の対話に対して使用することはできません。たとえば,クラアント/サーバー・アプリケーションで,あるサーバー・アプリケーションと 10 のクライアントが通信している場合は,各クライアントがそれぞれ一意のセキュリティ・コンテキストを持ち,サーバは 10 のセキュリティ・コンテキストを,各クライアントに対して 1 つずつ管理することになります。

コンテキストの開始時に,アプリケーションは「セキュリティ・コンテキスト管理関数」で説明されている各種のセキュリティ・オプションを選択できます。

アプリケーションがセキュリティ・コンテキストを確立するときの手順は,次のとおりです。 開始側と受け入れ側によって使われる関数呼び出しのいくつかは,コンテキストを完全に確立するために必要になります。

  1. 開始側は gss_init_sec_context() を呼び出すことによって受け入れ側とのセキュリティ・コンテキストを開始し,以前に取得した信任状と,受け入れ側によって使われる識別情報を渡します。

  2. gss_init_sec_context() 関数は,部分的に作成されたセキュリティ・コンテキストとトークン,およびステータス・コードを戻します。

    このトークンには,受け入れ側に送信する必要のある GSS-API 情報が入っています。トークンは開始側アプリケーションから見ると不透過ですが,アプリケーションはトークンの長さを認識しているため,受け入れ側にトークンを送信できます。

    関数を再度呼び出す必要があるかどうかはステータス・コードによって示されます。関数を再度呼び出す場合は,受け入れ側からリターン・トークンを受け取り,関数に渡さなくてはなりません。

    エラー・ステータスが戻されるときに,トークンが戻されることがあります。戻されたステータス・コードに関係なく,トークンは相手側のアプリケーションに送信される必要があります。

  3. 開始側は通信プロトコルを通じて,コンテキストの確立を待っている受け入れ側にトークンを送信します。

    トークンがどのようにして送信されるかは,アプリケーションに依存します。ただし GSS-API 標準では,コンテキスト確立時にトークンが生成された順番でトークンを送信するように定められています。

  4. 受け入れ側は,通信プロトコルからトークンを読み取り,gss_accept_sec_context() を呼び出して,以前に取得した信任状と,受け取ったトークンを渡します。

  5. gss_accept_sec_context() 関数は,ステータス・コードを戻し,場合によってはトークンも戻します。

    関数を再度呼び出す必要があるかどうかはステータス・コードによって示されます。関数を再度呼び出す場合は,開始側からリターン・トークンを受け取り,関数に渡さなくてはなりません。

    エラー・ステータスが戻されるときに,トークンが戻されることがあります。戻されたステータス・コードに関係なく,トークンは相手側のアプリケーションに送信される必要があります。

  6. gss_accept_sec_context() がトークンを戻した場合,受け入れ側は,セキュリティ・コンテキストの確立を続行するためにこのトークンを待っている開始側に,通信プロトコルを通じてトークンを送信する必要があります。

  7. 開始側はリターン・トークンを受け取ると,gss_init_sec_context() を呼び出してトークンを渡します。

手順 1 から 5 までは,開始側と受け入れ側の最低限のやり取りを示しています。手順 6 と 7 は,gss_init_sec_context() および gss_accept_sec_context() 関数の複数の呼び出しを例示しています。これらの関数は,メジャー・ステータス・コード GSS_S_CONTINUE が戻されると,ループに入ります。gss_init_sec_context() 関数からトークンが戻されたら,受け入れ側に戻す必要があります。GSS_S_CONTINUE が戻されると,受け入れ側からトークンが戻ってくるものと期待されるため,次の gss_init_sec_context() の呼び出しへの入力として渡されなければなりません。この動作は通常,Kerberos が相互認証を実行するときに発生します。

GSS_S_CONTINUE ステータスがメジャー・ステータス・コードとして戻され,呼び出しによって戻されたトークンがピア・アプリケーションに送信されると,ローカル・アプリケーション側でセキュリティ・コンテキストが完全に確立します。

gss_init_sec_context() 関数は次のパラメータを使います。

入力パラメータ  
initiator_cred_handle 開始側の信任状 (または信任状キャッシュからの省略時の信任状)。
target_name 受け入れ側の名前。
mech_type 要求されているセキュリティ・メカニズム (Kerberos 5)。
req_flags サービス・オプション。たとえば,DES3/DES 暗号化,信任状の委任,相互認証,リプレイ・メッセージの検出,順序外メッセージの検出など。
time_req 要求されたコンテキストの存続期間 (無視されます)。
input_chan_bindings チャネル・バインディング
input_token 受け入れ側から戻されたトークン。
出力パラメータ  
minor_status Kerberos 5 エラー・コード。
context_handle 開始するセキュリティ・コンテキスト。
actual_mech_type 使用されているセキュリティ・メカニズム (Kerberos 5)。
output_token 受け入れ側に送信されるトークン。
ret_flags このコンテキストがサポートしているサービス・オプションを識別するフラグ。
time_rec 受け取ったコンテキストの存続期間 (常に不定です)。

サンプル・プログラムから抜粋した下記のコードは,gss_init_sec_context() を呼び出して,次のオプションを使ってセキュリティ・コンテキストを確立する方法を示しています。

暗号化方式は指定されていないため,省略時の設定で,プリンシパル・データベースの信任状に割り当てられている暗号化方式に設定されます。

/***************************************************************/
 
char            szHostName[]      = "host@dev007.cybersafe.com";
OM_uint32       gMaj, gMin        = 0;
OM_uint32       req_flags         = GSS_C_MUTUAL_FLAG |
                                    GSS_C_REPLAY_FLAG |
                                    GSS_C_SEQUENCE_FLAG;
OM_uint32       req_time          = 3600;
OM_uint32       ret_flags         = 0;
OM_uint32       ret_time;         = 0;
gss_buffer_desc input_name        = GSS_C_EMPTY_BUFFER;
gss_buffer_desc input_token       = GSS_C_EMPTY_BUFFER;
gss_buffer_desc output_token      = GSS_C_EMPTY_BUFFER;
gss_buffer_t    token_handle      = GSS_C_NO_BUFFER;
gss_ctx_id_t    context_handle    = GSS_C_NO_CONTEXT;
gss_name_t      service_name      = GSS_C_NO_NAME;
gss_OID         actual_mech_type  = GSS_C_NO_OID;
 
/* Copy the host service principal name
   into the GSS buffer structure */
input_name.length = strlen( szHostName );
input_name.value  = strdup( szHostName );
 
/* Convert the host service principal name
   into GSS internal form */
gMaj = gss_import_name( &gMin,
                        &input_name, 
                        GSS_KRB5_NT_HOSTBASED_SERVICE_NAME,
                        &service_name );
 
/* Establish a context. The default claimant credential is
   specified. In that case, the credential is pulled from the
   credential cache. Alternatively, the claimant credential
   could have been acquired via gss_acquire_cred and passed
   to gss_init_sec_context. */
do { 
    token_handle = input_token.length ?
                   &input_token : GSS_C_NO_BUFFER;
 
    /* Initiate a security context with the Acceptor */
    gMaj = gss_init_sec_context( &gMin,
                                 GSS_C_NO_CREDENTIAL,
                                 &context_handle,
                                 service_name,
                                 GSS_C_NO_OID,
                                 req_flags,
                                 req_time,
                                 GSS_C_NO_CHANNEL_BINDINGS,
                                 token_handle, 
                                 &actual_mech_type,
                                 &output_token,
                                 &ret_flags,
                                 &ret_time);
 
 
    /* If there is a token to send, regardless of 
       error condition, then send it to the peer */
    if ( output_token.length != 0 ) {
        SendToken( &output_token );
    }
 
    /* Clear the buffers for the next iteration */
    Local_Release_Buffer( &input_token );
    gss_release_buffer( &tmpMinor, &output_token );
 
    /* Now is the proper time to check the status code */
    if ( GSS_ERROR( gMaj ) {
        /* Process error and exit */
    }
 
    /* If context establishment requires a token in response,
       then fetch it from the peer */
    if ( gMaj & GSS_S_CONTINUE_NEEDED ) {
        RecvToken( &input_token );
    }
 
} while ( gMaj & GSS_S_CONTINUE_NEEDED );
 
/***************************************************************/

コンテキストが不要になったら,gss_delete_sec_context() 関数を使って破壊する必要があります。サンプル・プログラムにこの例が含まれています。

gss_accept_sec_context() 関数は次のパラメータを使います。

入力パラメータ  
context_handle 確立しているセキュリティ・コンテキスト
acceptor_cred_handle 受け入れ側への信任状。
input_token_buffer 開始側からのトークン。
input_chan_bindings チャネル・バインディング。
出力パラメータ  
minor_status Kerberos 5 エラー・コード。
src_name 開始側の名前。
mech_type 使用されているセキュリティ・メカニズム (Kerberos 5)。
output_token 開始側に送信されるトークン。
ret_flags このコンテキストがサポートしているサービス・オプションを識別するフラグ。
time_rec 受け取ったコンテキストの存続期間 (常に不定です)。
delegated_cred_handle コンテキストの開始側から委任された信任状。

サンプル・プログラムから抜粋した下記のコードは,gss_accept_sec_context() を呼び出して,セキュリティ・コンテキストを確立する方法を示しています。

*****************************************************************
 
OM_uint32       gMaj, gMin       = 0;
OM_uint32       ret_flags        = 0;
OM_uint32       ret_time         = 0;
OM_uint32       ctx_flags        = 0;
gss_buffer_desc input_token      = GSS_C_EMPTY_BUFFER;
gss_buffer_desc output_token     = GSS_C_EMPTY_BUFFER;
gss_cred_id_t   delegated_cred   = GSS_C_NO_CREDENTIAL;
gss_ctx_id_t    context_handle   = GSS_C_NO_CONTEXT;
gss_name_t      src_name         = GSS_C_NO_NAME;
gss_OID         actual_mech_type = GSS_C_NO_OID;
 
/* Loop based on the example in
   "draft-ietf-cat-gssv2-cbind-07.txt" */
do {
    OM_uint32  tmpMinor = 0;
 
    /*  Fetch next security context token from the Initiator */
    RecvToken( &input_token );
 
    /*  Wait for the Initiator to try to establish a security
        context. The acceptor will use a previously acquired
        acceptor credential. */
    gMaj = gss_accept_sec_context( &gMin,
                                   &context_handle,
                                   cred_handle,
                                   &input_token, 
                                   GSS_C_NO_CHANNEL_BINDINGS,
                                   &src_name,
                                   &actual_mech_type,
                                   &output_token,
                                   &ret_flags, 
                                   &ret_time,
                                   &delegated_cred );
 
    /* If the authentication routine forms a token to send to
       the Initiator, then send it now -- before function error
       checking, so that if an error token is generated, the
       Initiator will receive it. */
    if ( output_token.length != 0 ) {
        SendToken( &output_token );
    }
 
    /* Clear the buffers for the next iteration */
    Local_Release_Buffer( &input_token );
    gss_release_buffer( &tmpMinor, &output_token );
 
    /* Now is the proper time to check the status code */
    if ( GSS_ERROR( gMaj ) ) {
        /* Process error and exit */
    }
 
} while ( gMaj & GSS_S_CONTINUE_NEEDED );
 
******************************************************************

コンテキストが不要になったら,gss_delete_sec_context() 関数を使って破壊する必要があります。サンプル・プログラムにこの例が含まれています。

C.7    手順 4: メッセージの交換

アプリケーションとそのピアの間で信任状とセキュリティ・コンテキストが取得された後で,メッセージを保護し,送信できます。ここでは,Application Security SDK で使用可能な,メッセージの保護に関するオプションについて説明します。

GSS-API 標準の Version 2 には,データを保護する次の 2 組の関数があります。

送信側のアプリケーションがこれらの関数の 1 つを呼び出すと,その関数によってトークンが戻されます。戻されたトークンには,完全性アルゴリズムを使って送信されているメッセージに対して計算された署名が含まれています。gss_wrap() の場合,トークンにはメッセージ自体も含まれます。その場合はオプションで,機密性のためにメッセージを暗号化できます。

Application Security SDK は,次の 4 つの完全性アルゴリズムを提供しています。

暗号化アルゴリズムは,DES3 と DES の 2 つが提供されています。

アプリケーションはその後,TCP/IP などの通信プロトコルを使って,受信側のアプリケーションにトークン (および,このトークンにメッセージが含まれていなければメッセージ) を送ります。受信側のアプリケーションは,この関数の対となっている関数を呼び出して,渡されたデータに対して同様の操作を実行します。

これらの関数は,データを保護するために,次の 3 つのオプションを提供しています。

  1. メッセージと署名を別々に送信する。

    このオプションを使うと,トークンには,送信側のアプリケーションによって gss_get_mic() 関数を使って作成された署名が含まれます。メッセージはトークンには含まれません。

    受信側のアプリケーションは,トークンとメッセージを受け取ると,gss_verify_mic() 関数を呼び出して署名をチェックし,メッセージの送信中にメッセージと署名が書き換えられていないことを確認します。

  2. メッセージと署名を一緒に送信する。

    このオプションを使うと,トークンには,送信側のアプリケーションによって gss_wrap() 関数を使って作成された署名が含まれます。メッセージはトークンの中にカプセル化されます。

    受信側のアプリケーションは,トークンとメッセージを受け取ると,gss_unwrap() 関数を呼び出して署名をチェックし,メッセージの送信中にメッセージと署名が書き換えられていないことを確認します。

  3. 暗号化されたメッセージと署名を一緒に送信する。

    これは,オプション 2 と同じですが,メッセージと署名は gss_wrap() 関数によって暗号化され,gss_unwrap() 関数によって復号されます。

各オプションは,分散型アプリケーションのデータを保護するときの特定の用途に対応するものです。

たとえば,アプリケーションに,保護する必要のあるデータと,保護する必要のないデータが含まれている場合,アプリケーションは保護すべきデータのみを保護するように選択できます。これらの判断基準は,データの長さと速度,効率,暗号化アルゴリズムの強度に応じて,アプリケーションに依存します。データ量が多い場合は,メッセージの一部だけを保護するのが効率的です。ただしメッセージ全体を保護することはめったにありません。

アプリケーションが gss_wrap() と機密性を使っている例を以下に示します。

アプリケーションがメッセージの送信中にその完全性が保護されたことを保証し,さらに,データをあるチャネルで送信し,チェックサムを ftp など別のアウト・オブ・バウンド (制御) チャネルで送信する必要がある場合,アプリケーションは下に示す gss_get_mic() 関数を使う必要があります。

C.7.1    gss_get_mic( ) と gss_verify_mic( ) の使用

gss_get_mic() を呼び出すと,アプリケーションは,ピア・アプリケーションが gss_verify_mic() を使ってチェックできる,データの署名を作成できます。これにより,メッセージの完全性,つまりメッセージとその署名が送信中に書き換えられていないことを保証できます。

これらの関数を使って開始側から受け入れ側へ,メッセージを送信する一連の手順は次のとおりです。

  1. 開始側が gss_get_mic() を呼び出し,署名を生成する対象のデータを渡します。

  2. この関数は,渡したデータの署名の入ったトークンを戻します。ただしデータ自体はトークンには含まれていません。

  3. 開始側が受け入れ側にデータを送信します。

    トークンとデータは,任意の順番での送信,別々のメッセージとしての送信,同じメッセージ内での送信,またはその他のオプションを指定しての送信が可能です。

  4. 開始側が受け入れ側へトークンを送ります。

  5. 受け入れ側は gss_verify_mic() を呼び出し,開始側から受け取ったデータとトークンを渡します。

  6. gss_verify_mic() 関数は,署名とデータを突合せたチェックが正常に終了したかどうかを示すステータスを戻します。

gss_get_mic() 関数には次のパラメータがあります。

入力パラメータ  
context_handle 使用しているセキュリティ・コンテキスト。
qop_req 要求された Quality Of Protection (QOP)。
message_buffer 保護するメッセージ。
出力パラメータ  
minor_status Kerberos 5 エラー・コード。
message_token 署名の入ったトークン。

サンプル・プログラムから抜粋した下記のコードは,この関数呼び出しを使ってメッセージを送信する方法を示しています。省略時の QOP が指定されます。この例では,セキュリティ・コンテキストに指定された暗号化タイプによって決まります。

/****************************************************************/
 
char             szMessage[]   = "This is a test message";
OM_uint32        gMaj, gMin    = 0;
gss_buffer_desc  input_buffer  = GSS_C_EMPTY_BUFFER;
gss_buffer_desc  output_buffer = GSS_C_EMPTY_BUFFER;
gss_qop_t        qop_req       = GSS_C_QOP_DEFAULT;
 
/* Stuff plaintext message into the input buffer*/
input_buffer.value  = strdup( szMessage );
input_buffer.length = strlen( szMessage );
 
/* Create a message integrity code (MIC) from the message */
gMaj = gss_get_mic( &gMin,
                    context_handle,
                    qop_req,
                    &input_buffer,
                    &output_buffer );
 
/* Send the MIC token */
SendToken( &output_buffer );
 
/****************************************************************/

トークンに関連付けられている記憶域は,使用後はメモリ・リークを避けるために gss_release_buffer() 関数を使って解放する必要があります。

gss_verify_mic() 関数には次のパラメータがあります。

入力パラメータ  
context_handle 使用しているセキュリティ・コンテキスト。
message_buffer チェックするメッセージ。
token_buffer 署名の入ったトークン。
出力パラメータ  
minor_status Kerberos 5 エラー・コード。
qop_state 使用された QOP。

gss_verify_mic() 関数から GSS_S_COMPLETE が戻されると,署名は正常に検査されたことを示します。

サンプル・プログラムから抜粋した下記のコードは,この関数呼び出しを使ってメッセージを受信する方法を示しています。

/****************************************************************/
 
char             szMessage[]    = "This is a test message";
OM_uint32        gMaj, gMin     = 0;
gss_buffer_desc  input_buffer   = GSS_C_EMPTY_BUFFER;
gss_buffer_desc  message_buffer = GSS_C_EMPTY_BUFFER;
gss_qop_t        qop_state      = 0;
 
/* Stuff plaintext message into the message buffer*/
message_buffer.value  = strdup( szMessage );
message_buffer.length = strlen( szMessage );
 
/* Receive the MIC token */
RecvToken( &input_buffer );
 
/* Verify the message against the message integrity code (MIC) */
gMaj = gss_verify_mic( &gMin,
                       context_handle,
                       &message_buffer,
                       &input_buffer,
                       &qop_state );
 
/****************************************************************/

C.7.2    gss_wrap( ) と gss_unwrap( ) の使用

gss_wrap() を呼び出すと,アプリケーションは,ピア・アプリケーションが gss_unwrap() を使ってチェックできる,データをラップできます。これにより,メッセージが送信中に書き換えられていないことを保証できます (メッセージの完全性)。

さらに,アプリケーションは,機密性のためにデータを暗号化し,データを誰にも見えないように保証できます。データをトークンにカプセル化すると,ネットワーク上で送信されるデータのための安全なエンベロープが作成されます。

これらの関数を使って開始側から受け入れ側へ,メッセージを送信する一連の手順は次のとおりです。

  1. 開始側は,トークンにラップしたいデータを使って,gss_wrap() を呼び出します。機密性が同時に呼び出されることもあります。

  2. データと,そのデータの署名の入ったトークンが戻されます。機密性が要求された場合は,両方とも暗号化されます。

  3. 開始側は受け入れ側にトークンを送ります。

  4. 受け入れ側は gss_unwrap() を呼び出し,開始側から受け取ったデータとトークンを渡します。

  5. gss_unwrap() 関数は,署名をチェックするステータス・コードと,元のデータの両方を戻します。最初に機密性が要求されていた場合は,データの復号も行われます。

gss_wrap() 関数には次のパラメータがあります。

入力パラメータ  
context_handle 使用しているセキュリティ・コンテキスト。
conf_req_flag 機密性の要求 (真または偽)。
qop_req 要求された Quality Of Protection (QOP)。
input_message_buffer 保護するメッセージ。
出力パラメータ  
minor_status Kerberos 5 エラー・コード。
conf_state 機密性の確認 (真または偽)。
conf_state 保護されたメッセージ。

サンプル・プログラムから抜粋した下記のコードは,この関数呼び出しを使って暗号化されたメッセージを送信する方法を示しています。省略時の QOP が指定されます。この例では,セキュリティ・コンテキストに指定された暗号化タイプによって決まります。

/**********************************************************/
char             szMessage[]   = "This is a test message";
OM_uint32        gMaj, gMin    = 0;
int              conf_req_flag = 1;
i_32             conf_state    = 0;
gss_buffer_desc  input_buffer  = GSS_C_EMPTY_BUFFER;
gss_buffer_desc  output_buffer = GSS_C_EMPTY_BUFFER;
gss_qop_t        qop_req       = GSS_C_QOP_DEFAULT;
 
/* Stuff plaintext message into the input buffer*/
input_buffer.value  = strdup( szMessage );
input_buffer.length = strlen( szMessage );
 
/* Wrap (Seal) the message into a token */
gMaj = gss_wrap( &gMin,
                 context_handle,
                 conf_req_flag,
                 qop_req,
                 &input_buffer,
                 &conf_state,
                 &output_buffer );
 
/* Send the message token */
SendToken( &output_buffer );
/**********************************************************/

保護されたメッセージに関連付けられている記憶域は,使用後はメモリ・リークを避けるために gss_release_buffer() 関数を使って解放する必要があります。

gss_unwrap() 関数には次のパラメータがあります。

入力パラメータ  
context_handle 使用しているセキュリティ・コンテキスト。
input_message_buffer ラップ解除,チェック,必要であれば復号を行うメッセージ。
出力パラメータ  
minor_status Kerberos 5 エラー・コード。
output_message_buffer ラップ解除されたメッセージ。
conf_state 機密性の確認 (真または偽)。
qop_state 使用された QOP。

gss_unwrap() 関数から GSS_S_COMPLETE が戻されると,署名は正常に検査されたことを示します。

サンプル・プログラムから抜粋した下記のコードは,この関数呼び出しを使ってメッセージを受信する方法を示しています。

/****************************************************************/
 
char             szMessage[256];
OM_uint32        gMaj, gMin    = 0;
i_32             conf_state    = 0;
gss_buffer_desc  input_buffer  = GSS_C_EMPTY_BUFFER;
gss_buffer_desc  output_buffer = GSS_C_EMPTY_BUFFER;
gss_qop_t        qop_state     = 0;
 
/* Receive the message token */
RecvToken( &input_buffer );
 
/* Unwrap (Unseal) the message token */
gMaj = gss_unwrap( &gMin,
                   context_handle,
                   &input_buffer, 
                   &output_buffer,
                   &conf_state,
                   &qop_state );
 
/* Extract plaintext message from the output buffer*/
if ( output_buffer.value != NULL ) {
    strcpy( szMessage, output_buffer.value );
}
 
/****************************************************************/

ラップ解除したメッセージに関連付けられている記憶域は,使用後はメモリ・リークを避けるために gss_release_buffer() 関数を使って解放する必要があります。

C.8    手順 5: セキュリティ・コンテキストの終了

一方のアプリケーションが,そのピアとの通信を完了すると,セキュリティ・コンテキストを終了することができます。GSS-API 標準では,開始側と受け入れ側のアプリケーションによってセキュリティ・コンテキストを終了できるようになっています。

セキュリティ・コンテキストを終了する手順は,開始側も受け入れ側も同じです。アプリケーションとピアの間に複数のセキュリティ・コンテキストが存在している場合は,個々のコンテキストを別々に終了する必要があります。

gss_delete_sec_context() 関数には次のパラメータがあります。

入力パラメータ  
context_handle 削除するセキュリティ・コンテキスト。
出力パラメータ  
minor_status Kerberos 5 エラー・コード。
output_token ローカルでの削除を要求する GSS_C_NO_BUFFER を指定します。HP ではこれを推奨しています。

サンプル・プログラムから抜粋した下記のコードは,セキュリティ・コンテキストを終了し,以前に取得した信任状を解放する方法を示しています。

/****************************************************************/
 
/* The V2 GSS_API specs recommend setting the output token
   parameter to NULL to signify that no token is to be
   returned. */
 
gMaj = gss_delete_sec_context( &gMin,
                               &context_handle,
                               GSS_C_NO_BUFFER );
 
context_handle = GSS_C_NO_CONTEXT;                     
     :
     :
     :
..gMaj = gss_release_cred( &gMin,
                         &cred_handle );
 
cred_handle = GSS_C_NO_CREDENTIAL;
 
/****************************************************************/

C.9    高度な概念

GSS-API 標準に対する HP のエクステンションにより,アプリケーション側でそのセキュリティ環境をより管理できるようになります。これらのエクステンションでは,次のことが可能です。

これらのエクステンションは,メカニズムと実装に固有です。エクステンションを使うと,アプリケーションの移植性に影響を及ぼすことがあります。たとえば,HP の DES3 の実装は,他の GSS-API ベンダの DES3 との相互運用性がありません。

C.9.1    初回信任状の取得

標準の GSS-API 関数を使って Kerberos 5 を扱うときには,アプリケーションは GSS-API によって保護したアプリケーションを実行する前に,チケット・グランティング・チケット (TGT) を取得している必要があります。ユーザは,kinit またはこれに相当するアプリケーション (たとえば,HP の Single SignOn) を実行することによって TGT を取得できます。

いくつかの状況では,ユーザに,TGT の取得機能を備えたプログラムを 1 つだけ実行させるのが望ましいこともあります。このため,Application Security SDK には,セキュリティ・サーバから初回信任状を取得するために使用できるエクステンション関数が含まれています。

csf_gss_acq_user() 関数は,秘密鍵または公開鍵認証と,オプションで DES3 暗号化を使ってアプリケーション内から初回信任状を取得するHP のエクステンションです。

この関数は,ユーザ・コンテキストを確立するときに,このユーザの信任状キャッシュがなければこれを作成します。信任状キャッシュが存在していても,要求された信任状に一致するものがない場合,キャッシュは再初期化されます。この場合,アプリケーションは他のアプリケーションがこの信任状キャッシュを使っていないことを確認する必要があります。

この関数は,アプリケーションが表示しなければならないプロンプトとラベルも提供します。アプリケーションは,結果の応答を収集して,それを GSS に戻す必要があります。

csf_gss_acq_user() 関数には次のパラメータがあります。

入力パラメータ  
user_name 初回信任状を必要とするユーザまたはサービスの名前。指定がなければ,省略時のプリンシパルまたはログイン名を使用できます。
desired_mechs 要求されているセキュリティ・メカニズム (Kerberos 5)。
options 初回信任状のプロトコル・キー,属性 (存続期間,延長可能,転送可能,事前認証,代理可能),および暗号化方法 (DES または DES3) を決定するオプション。
user_response ユーザからの応答をアプリケーションのプロンプトに渡します。
出力パラメータ  
minor_status Kerberos 5 エラー・コード。
user 取得されているユーザ・コンテキスト。
user_prompt プロンプトをアプリケーションに渡します。
user_label プロンプト情報をアプリケーションに渡します。
prompt_state プロンプト表示のヒントをアプリケーションに渡します。
prompting_mech 使用されているセキュリティ・メカニズム (Kerberos 5)。
pwd_exp_time ユーザのパスワードの有効期限。

csf_gss_acq_user() 関数は,次のようにして使います。

この関数はループ関数です。つまり,複数回呼び出す必要が生じることもあります。

他にも,初回信任状の管理に利用できる特殊な HP 関数があります。 たとえば,csf_gss_inq_user() は TGT の問い合わせを行います。不要になったユーザ・コンテキストに対応する記憶域を解放するには,csf_gss_release_user() を使います。

サンプル・プログラムから抜粋した下記のコードは,次のオプションを使って初回信任状のためのユーザ・コンテキストを確立する方法を示しています。

また,パスワード,チャレンジ,ワン・タイム・パスワード (OTP) のプロンプトがあるかどうかもチェックします。 プリンシパル名は以前にインポートされています。不要になった記憶域を解放するための呼び出しは示していません。

/****************************************************************/
 
OM_uint32             gMaj           = 0;
OM_uint32             gMin           = 0;
i_32                  done           = 0;
i_32                  prompt_state   = CSF_GSS_C_USER_STATE_NULL;
int                   optCount       = 0;
gss_buffer_desc       user_prompt1   = GSS_C_EMPTY_BUFFER;
gss_buffer_desc       user_label1    = GSS_C_EMPTY_BUFFER;
gss_buffer_desc       response1      = GSS_C_EMPTY_BUFFER;
gss_buffer_t          user_prompt    = &user_prompt1;
gss_buffer_t          user_label     = &user_label1;
gss_buffer_t          response       = GSS_C_NO_BUFFER;
csf_gss_user_t        gss_user       = CSF_GSS_C_NO_USER;
gss_OID               prompting_mech = GSS_C_NO_OID;
csf_gss_mech_opt_desc opts[10];
char                  buff[256];
time_t                pwd_exp_time;
 
/* Set up the csf_gss_acq_user options */
opts[optCount].mechOID = rfc_krb5_c_OID;
opts[optCount].id  = CSF_GSS_C_ACQ_USER_OPT_FORWARDABLE;
++optCount;
 
opts[optCount].mechOID = rfc_krb5_c_OID;
opts[optCount].id  = CSF_GSS_C_ACQ_USER_OPT_LIFETIME;
opts[optCount].val = "10h";
++optCount;
 
opts[optCount].mechOID = rfc_krb5_c_OID;
opts[optCount].id  = CSF_GSS_C_ACQ_USER_OPT_RENEWABLE;
opts[optCount].val = "48h";
++optCount;
 
opts[optCount].mechOID = rfc_krb5_c_OID;
opts[optCount].id      = CSF_GSS_C_ACQ_USER_OPT_DES3;
++optCount;
 
opts[optCount].mechOID = GSS_C_NO_OID;
 
/* Acquire the user context */
do {
    gMaj = csf_gss_acq_user( &gMin,
                             principal_name,
                             rfc_krb5_c_OID_set,
                             opts,
                             response,
                             &gss_user,
                             user_prompt,
                             user_label,
                             &prompt_state,
                             &prompting_mech,
                             &pwd_exp_time );
 
 
    /* Check whether user needs to provide more information */
    if ( gMaj & GSS_S_CONTINUE_NEEDED ) {
 
 
        switch ( prompt_state ) 
        {
            case CSF_GSS_C_USER_STATE_PASSWORD_NOECHO:
            case CSF_GSS_C_USER_STATE_PASSWORD_ECHO:
            printf( "Password information is requested...\n");
break;
 
            case CSF_GSS_C_USER_STATE_CHALLENGE_NOECHO:
            case CSF_GSS_C_USER_STATE_CHALLENGE_ECHO:
            printf( "Challenge information is requested...\n");
break;
 
            case CSF_GSS_C_USER_STATE_OTP_NOECHO:
            case CSF_GSS_C_USER_STATE_OTP_ECHO:
            printf( "OTP information is requested...\n");
break;
 
            default:
            printf( "Unrecognized prompt state.\n");
        }
 
        printf( "%s\n", user_label->value);
        printf( "Enter %s", user_prompt->value);
        fflush(stdout);
 
        response = &response1;
 
        fgets(buff, 256, stdin);
        response->value  = buff;
        response->length = strlen(buff);
        buff[response->length - 1] = '\0';
    }
    else {
        done = 1;
    }
 
} while (!done);
 
/***************************************************************/

C.9.2    必要な時刻同期

受け入れ側アプリケーションのホストは,信任状を付与するセキュリテイ・サーバとの時間のずれが 5 分以内である必要があります。受け入れ側アプリケーションのホストとセキュリティ・サーバとの時間のずれが 5 分以内ならば,受け入れ側アプリケーションとのずれも 5 分以内である必要があります。クロック・スキューと呼ばれるずれが 5 分を超えている場合,認証は失敗します。あるアプリケーションからそのピアへ信任状を転送しているときは,すべてのシステムのクロックを 5 分以内で同期させる必要があります。

ホストのクロックで 5 分の差を許容しているため,チケットの存続期間の残りが時差の上限に満たない場合,セキュリティ・サーバは実際の有効期限よりも前にチケットを拒否することがあります。 時差の制限に応じて必要となる実際の有効存続期間は,開始側のクロックがセキュリティ・サーバのクロックよりも進んでいるのか,遅れているのかによって異なりますが,範囲は 1 分から 5 分です。時差の上限に関する GSS の失敗の例として,関数 gss_init_sec_context() は,開始側の Kerberos 信任状の有効期限が時差の範囲内にあると失敗し,context_handle パラメータを GSS_C_NO_CONTEXT に設定します。これが発生すると,この関数は Kerberos エラー,"Credentials Not Found (信任状が見つかりません)" (16 進値 C0001507) を戻します。この場合,開始側アプリケーションは,gss_init_sec_context() を使って受け入れ側アプリケーションとのセキュリティ・コンテキストを確立する前に,新しい初回信任状 (TGT) をセキュリティ・サーバから取得する必要があります。

C.9.3    DES3 暗号化の使用

Application Security SDK は,DES および DES 3 暗号化の両方をサポートしています。 ただし,単一のセキュリティ・コンテキストに対して複数の暗号化システムは許可されていません。

DES3 暗号化を使ってメッセージを暗号化できるようにするには,次の条件が満たされている必要があります。

必ずしも HP エクステンションを使って DES3 を有効にする必要はありません。ただし,要求された暗号化が使われているかどうかを常に確認しなければなりません。上記の条件を満たしていない場合,コンテキストは,DES3 から DES へレベルが下がることがあります。コンテキストを確立した後で,csf_gss_get_context_options() を使って戻されたフラグを調べて,DES と DES3 のどちらが使用されたかを確認してください。

C.10    GSS-API 関数のステータス・コード

GSS-API 関数には,メジャー・ステータスとマイナー・ステータスの 2 つのリターン・ステータス・コードがあります。アプリケーションは,ステータス・コードを使って GSS-API から戻されるエラーを,効率よく処理することが重要です。

メジャー・ステータスは,GSS-API 関数のエラー・コードです。メジャー・ステータス・コードは,ルーチン (関数) エラー,呼び出しエラー,補足情報の 3 つのビット・フィールドで構成されます。

マイナー・ステータス はメカニズムに固有のエラー・コードです。GSS_ERROR() によって Kerberos 5 メカニズムに関するエラーが示されている場合に,追加のエラー情報が提供されることがあります。

エラー・コードがあるかどうかは,メジャー・ステータスを GSS_ERROR() マクロに送り,得られた結果を検査することで分かります。ゼロが戻された場合,エラーはありません。その他の値が戻された場合は,エラーを示しています。

警告

エラーの有無は,GSS_ERROR() マクロを使って調べる必要があります。ステータスを数字のゼロと比較しないでください。

GSS_ERROR() マクロは,ルーチン (関数) エラー・フィールド,呼び出しエラー・フィールド,または補足情報フィールドエラーがあるかどうかを調べることによってエラーを示します。次のコードは,この使い方の例を示しています。

/***************************************************************/
 
OM_uint32       status_value = <--- value passed in to test
OM_uint32       majErr, minErr  = 0;
OM_uint32       message_context = 0;
gss_buffer_desc status_string   = GSS_C_EMPTY_BUFFER;
 
if ( GSS_ERROR(status_value) ||
     GSS_SUPPLEMENTARY_INFO(status_value) ) {
 
    /* First process the Major status code */
    do {
        /* Get the status string associated
           with the Major (GSS=API) status code */
        majErr = gss_display_status( &minErr,
                                     status_value,
                                     GSS_C_GSS_CODE,
                                     GSS_C_NO_OID,
                                     &message_context,
                                     &status_string );
 
        /* Print the status string */
        printf( "Major status string: %s\n",
        (char*)status_string.value );
 
        /* Free the status string buffer */
        gss_release_buffer( &minErr, &status_string );
 
    } while( message_context && !GSS_ERROR( majErr ) );
 
    /* Then process the Minor status code */
    do {
        /* Get the status string associated
           with the Minor (mechanism) status code */
        majErr = gss_display_status( &minErr,
                                     status_value,
                                     GSS_C_MECH_CODE,
                                     GSS_C_NO_OID,
                                     &message_context,
                                     &status_string );
 
        /* Print the status string */
        printf( "Minor status string: %s\n",
        (char*)status_string.value );
 
        /* Free the status string buffer */
        gss_release_buffer( &minErr, &status_string );
 
    } while( message_context && !GSS_ERROR( majErr ) );
}
 
/***************************************************************/

補足情報フィールドには,関数の追加情報が提供されます。たとえば,gss_init_sec_context() 関数がエラーを示すメジャー・ステータス・コードを戻した場合は,補足情報フィールドに,gss_init_sec_context() にアプリケーションのもう一方からのレスポンス・トークンが必要であると示されていることがあります。別の例では,関数 gss_unwrap() がメジャー・ステータス・コードを戻した場合,補足情報フィールドには,エラーの原因が順序外のトークンであるか,トークンのリプレイであるか,または古いトークンであることを示しています。

補足情報の値は,メジャー・ステータス・コード名前付きの識別子の AND をとることによって検査します。下記のコード例は,gss_unwrap() がリプレイを検出した場合に発生する処理を示しています。

/***************************************************************/
 
major_status = gss_unwrap(. . .);
if (GSS_ERROR(major_status)) {
   /* An error has occurred. */
   . . . 
   if (major_status & GSS_S_DUPLICATE_TOKEN) {
     /* The token is a replay of a previous token. */
     printf ("Warning: Replay detected\n");
   }
}
 
/***************************************************************/

C.10.1    マイナー・ステータス・コード

Kerberos メカニズムのマイナー・エラー・コードは,include/csf/sts および include/csfc5/sts ディレクトリの .hs ファイルにあります。

これらのエラー・コードはどれも,アプリケーションから参照でき,その原因となった Kerberos のエラー状況に応じてコードを分岐させることもできます。アプリケーションは,値を定義するマクロを参照する必要があります (#define の後のシンボル)。

通常,マイナー・エラーは,Kerberos の構成,またはプリンシパル・データベースのプリンシパルに問題がることを示します。

C.11    サンプル・プログラム

Application Security SDK には,サンプルのクライアント/サーバ・アプリケーションが含まれています。プログラムは,GSS-API 関数の使用例を示します。サンプル・プログラムでは,下記の GSS-API 関数を使っています。

クライアント・プログラムは,サーバ・プログラムとのセキュリティ・コンテキストを開始します。セキュリティ・コンテキストが確立された後,クライアントとサーバは,保護されたメッセージを交換します。クライアント・プログラムとサーバ・プログラムは,同じレルム内の 2 つのシステム,または (レルム間認証の設定がなされている) 異なるレルムの 2 つのシステムに分散できます。

クライアントは,呼び出されるたびにサーバとのやり取りを 1 回または複数回実行します。サーバとの 1 回のやり取りは,主に次の手順で行われます。

  1. TCP/IP 接続が確立されます。

  2. (オプションで,省略時には) クライアントとサーバは GSS-API コンテキストを確立し,サーバはクライアントの識別情報を表示します。

  3. クライアントがサーバにメッセージを送信します。メッセージは,プレーン・テキスト,暗号処理によって「署名」された暗号化されていない形式,または暗号化された形式 (省略時の設定) のいずれかになります。

  4. サーバは,(必要であれば) メッセージを復号し,(もしあれば) 署名をチェックし,メッセージを表示します。

  5. サーバは,メッセージの受け入れ確認のために,署名ブロック (省略時の場合) または空のトークンをクライアントに戻します。

  6. サーバが署名ブロックを送信すると,クライアントはこれをチェックし,チェックが終了したことを示すメッセージを表示します。

  7. クライアントは,サーバに空のブロックを送信して,やり取りが終了したことを伝えます。

  8. クライアントとサーバは,TCP/IP 接続を閉じて,GSS-API コンテキストを破壊します。

ソース・コード 説明
gss-server.c メインのサーバ・ソース・コード。
gss-client.c メインのクライアント・ソース・コード。
gss-misc.h その他のタスクのヘッダ・ファイル。
gss-misc.c その他のタスクを実行します。
Makefile_CPQ ビルド・ファイル。
README 情報ファイル。

次のダイアグラムは,GSS 関数がサンプル・プログラムの中でどのように実装されているかを示しています。

C.11.1    サンプル・プログラムのビルド

HP では,サンプル・コードを別の場所にコピーして,変更が必要になった場合はオリジナルのコードを保存しておくことを推奨しています。提供されている makefile (Makefile_CPQ) は,ほとんど,あるいはまったく変更する必要がありません。省略時の場合,デバッグは無効です。

実行可能プログラムをビルドするには,次の make コマンドを使います。

C.11.2    サンプル・プログラムの実行

ここでは,以下について説明します。

C.11.2.1    前提条件

サンプル・プログラムを実行するには,次の要件を満たしておく必要があります。

  1. クライアントのプリンシパルを定義する。

    クライアント・プログラムは,プリンシパルの host/host_name@REALM を使って認証します (host_name は受け入れ側ホストの完全修飾ドメイン名,REALM は受け入れ側ホストの省略時のレルムです。したがって,プリンシパル host/host_name@REALM はセキュリティ・サーバ (KDC) に登録されていなければなりません。

  2. サーバ・プリンシパルを取り出す。

    サーバのホスト・プリンシパルがサービス鍵テーブル・ファイル (v5srvtab) にあり,サービス鍵テーブル・ファイルを,サーバ・プログラムから読み取ることができなければなりません。サービス鍵テーブル・ファイルがセキュリティ・サーバにない場合は,ホスト・プリンシパルを取り出すことで作成できます。

  3. クライアントのプリンシパルを,プリンシパル・データベースに追加する。

    ホストでサーバを実行するには,service_name に対応するプリンシパルが,サーバ・ホストの省略時の鍵テーブル (/krb5/v5srvtab) にあり,gss-server プロセスがこの鍵テーブルを読み取ることができなければなりません。たとえば,サービス名 "sample@server" は,Kerberos のプリンシパル "sample/KDChost.domain.com@REALM" に対応します。

C.11.2.2    サンプル・プログラムの設定

必ず,サンプル・サーバ・プログラムを先に実行し,その後サンプル・クライアント・プログラムを実行してください。サンプルの出力を別々に確認できるように,各プログラムを別々のシェルで実行します。クライアントとサーバは,同じマシン実行することも,別々のマシンで実行することもできます。

クライアント/サーバ・プログラムは,必須のコマンド行引数を受け取ります。スイッチはすべてオプションです。

サーバ・プログラムには次の引数が必要です。

クライアント・プログラムには次の引数が必要です。

host

サーバを実行するホスト。

service_name

サーバが接続の確立に使うサービス名。

gss-server が gss-client とは別のマシンで実行していて,gss-client を実行するときにサービス名にホスト名を指定しない場合は,gss-client に対して指定するサービス名にサーバのホスト名を指定する必要があります。

msg

メッセージ。

複数の単語の場合は,次のようにメッセージを二重引用符で囲みます。

# gss-client unix1 sample@REALM "Hello Kerberos"

C.11.2.3    サーバのコマンド行スイッチ (省略可能)

以下に,サーバのコマンド用スイッチについて説明します。スイッチはすべて省略可能です。

-port 接続を受け入れる TCP ポート。
-once 1 回のやり取りが終わったら,継続せずに終了するようにサーバに指定します。
-inetd inetd を経由せずに実行して,ネットワーク・ポートにバインドせずに,stdin のクライアントとやり取りするようにサーバに指定します。-once が暗黙のうちに指定されます。
-export クライアントとのコンテキストの確立後,gss_export_sec_context() 関数をテストするようサーバに指定します。
-logfile サーバの出力を stdout ではなくファイルに送るときの出力先ファイル。

C.11.2.4    クライアントのコマンド行スイッチ (省略可能)

以下に,クライアントのコマンド用スイッチについて説明します。スイッチはすべて省略可能です。

-port 接続先の TCP ポート。省略時のポートは 4444。
-mech 使用する GSS-API メカニズムの OID。
-d 信任状をサーバに委任するようクライアントに指定します。Kerberos GSS-API メカニズムの場合,これは,転送可能 TGT がサーバに送信され,サーバの信任状キャッシュに格納されることを意味します (これを動作させるには,kinit -f でチケットを取得する必要があります)。
-f msg 引数が,実際にはファイルの名前であり,その内容をメッセージとして使う必要があることをクライアントに指定します。
-q 表示を抑制して,エラー・メッセージだけを表示するようにクライアントに指定します。
-ccount クライアントがサーバと開始する必要があるセッションの数 (「接続数」) を指定します。
-mcount 各セッションでサーバに送信すべきメッセージの回数 (「メッセージ数」) を指定します。
-na サーバとの認証をまったく行わないようクライアントに指定します。-nw,-nx,-nm が暗黙のうちに指定されます。
-nw メッセージを「ラップ」しないようクライアントに指定します。-nx が暗黙のうちに指定されます。
-nx メッセージを暗号化しないようクライアントに指定します。
-nm 暗号化を使ったチェックサム (「MIC」) を戻すことをサーバに要求しないようクライアントに指定します。

引数が指定されていない場合やプログラムが正しく使われていない場合は,クライアント/サーバ・サンプルの使用法のメッセージが表示されます。

# gss-server
Usage: gss-server [-port port] [-verbose] [-once]
       [-inetd] [-export] [-logfile file] [service_name]
 
# gss-client
Usage: gss-client [-port port] [-mech mechanism] [-d]
       [-f] [-q] [-ccount count] [-mcount count]
       [-na] [-nw] [-nx] [-nm] host service msg

C.11.3    サンプル・プログラムの出力

ここでは,サンプルのクライアント・サーバ・プログラムの出力を取り上げます。ここでは,クライアントからはメッセージとしてテキスト・ファイルを渡し,サーバはそのクライアントを認証してメッセージを表示しています。

# gss-server -verbose -once sample@REALM
Server waiting:
Received token (size=600): 
60 82 02 54 06 05 2b 05 01 05 02 01 00 6e 82 02 
47 30 82 02 43 a0 03 02 01 05 a1 03 02 01 0e a2 
07 03 05 00 20 00 00 00 a3 82 01 56 61 82 01 52 
30 82 01 4e a0 03 02 01 05 a1 15 1b 13 43 59 42 
45 52 4e 54 2e 5a 4b 33 2e 44 45 43 2e 43 4f 4d 
a2 28 30 26 a0 03 02 01 03 a1 1f 30 1d 1b 06 73 
61 6d 70 6c 65 1b 13 63 79 62 65 72 6e 74 2e 7a 
6b 33 2e 64 65 63 2e 63 6f 6d a3 82 01 04 30 82 
01 00 a0 03 02 01 05 a1 03 02 01 01 a2 81 f3 04 
81 f0 8e 80 d6 1d b4 11 51 61 75 24 f4 e4 96 c5 
db 1b ba 94 be c1 60 11 1a 24 c3 13 ae 22 50 90 
e2 ba 18 7b 9e 8f 6a 42 ca fa 96 b8 cf f0 8c 3f 
b8 ea 33 e9 21 24 ab ab e2 7e 4a 90 ee 75 93 11 
99 4e 15 ad 2e 47 83 5b de 74 eb b7 92 ad 86 e6 
27 fd c0 02 13 6d 56 38 3d 7e 80 dc ea a0 1c 79 
37 34 6f fa 4b dc 79 ed 2b ee ef 93 37 ae 6c 1f 
2c 83 62 c1 7a 0b 5a aa 10 47 e4 70 1d 31 9c 2c 
24 ee 8e 69 4a e2 c2 cd 7e 52 d4 ff 19 d6 d4 77 
e9 ee 78 19 e8 2d 5b 31 5c a0 89 28 f5 b2 e2 ef 
bf 2a 12 b5 1b 88 e3 e8 a3 21 5b d5 93 a1 21 44 
77 e8 e1 71 f3 2f b8 e1 06 20 fe 21 42 9a f5 bf 
e3 7b 55 76 a2 54 34 05 43 14 0b aa 2e d2 da 91 
31 02 8d 65 53 fe 4d 32 b6 b6 31 6f b2 7c d4 77 
bb 87 0f 85 6d 61 8d 2c 21 e8 be 3d fb fd a7 72 
bd 71 a4 81 d3 30 81 d0 a0 03 02 01 05 a1 03 02 
01 00 a2 81 c3 04 81 c0 aa b1 ae d7 0a 9b 75 c9 
ce ca b4 b1 1d a4 a4 4b bc 3a 73 4d b8 9e c0 fb 
51 44 8a 67 8d ad 25 87 6e 66 ed bf d7 fb fc b1 
6b 38 89 74 2b f8 eb 04 be 76 70 03 e3 2f db 7d 
15 53 53 9e 8d e4 f1 a1 60 b6 01 33 42 90 60 a5 
4c 75 dd af af 64 75 86 5a f8 25 57 c1 22 bc 12 
b1 54 c9 c1 0b a6 27 c0 44 2a 84 48 a6 6a 00 62 
f8 4d d7 27 9e 35 a5 74 2c 8f 04 c0 a8 c4 48 b6 
d9 52 84 40 5b 19 fe 4d bf eb 07 d0 e0 f9 46 8c 
72 5b bc df d0 0e 55 4a e2 e8 39 10 83 63 9f 02 
cd 07 8b 00 f9 d6 46 77 29 6d 13 64 e4 3c b3 53 
f7 46 12 9c 88 8b 5d e6 9e 05 f2 f7 6d 4e d8 15 
dd eb 9b a6 37 28 77 9a 
Sending accept_sec_context token (size=107):
60 69 06 05 2b 05 01 05 02 02 00 6f 5e 30 5c a0 
03 02 01 05 a1 03 02 01 0f a2 50 30 4e a0 03 02 
01 05 a1 03 02 01 00 a2 42 04 40 b1 61 8f 22 03 
93 d2 d4 df 6f 6e 19 99 99 68 64 78 53 27 22 8a 
c4 e8 42 b3 b5 23 3f 5d 0d 6a 6d 87 42 7b ca 8b 
10 13 ff 34 66 23 cf 75 a0 24 e9 4a a7 d6 cd 9c 
e2 a5 1b 98 55 02 ba 85 e8 3c b3 
context flag:GSS_C_MUTUAL_FLAG
context flag:GSS_C_REPLAY_FLAG
context flag:GSS_C_CONF_FLAG
context flag:GSS_C_INTEG_FLAG
Accepted connection using mechanism OID { 1 2 840 113554 1 2 2 }.
Accepted connection: "user@REALM"
Message token (flags=228):
60 57 06 05 2b 05 01 05 02 02 01 dd fa de fa ff 
ff e7 ad 91 9a ca e2 08 aa 32 27 86 fa 8a 0c 17 
44 18 9c 8c 7b f4 65 8c 63 88 6f be 70 f0 a8 ef 
95 17 da 92 48 44 e6 70 1c 4a 80 97 c0 f3 d3 34 
39 1f 03 b3 55 df 50 75 f0 40 9d 8a 9b 5d 0f aa 
3d 6b a0 c6 6d 34 42 29 58 
Received message: "
Hello Kerberos.
I am a text file.
"
NOOP token
#

以下は,クライアントからの出力を test というテキスト・ファイルに送っています。

# gss-client -f unix1 sample@REALM "test"
Sending init_sec_context token (size=600)...continue needed...
context flag:GSS_C_MUTUAL_FLAG
context flag:GSS_C_REPLAY_FLAG
context flag:GSS_C_CONF_FLAG
context flag:GSS_C_INTEG_FLAG
"user@REALM" to "sample/host.domain@REALM", lifetime -1, 
flags 1b6, locally initiated, open
Name type of source name is { 1 2 840 113554 1 2 2 1 }.
Mechanism { 1 2 840 113554 1 2 2 } supports 7 names
  0: { 1 2 840 113554 1 2 1 1 }
  1: { 1 2 840 113554 1 2 1 2 }
  2: { 1 2 840 113554 1 2 1 3 }
  3: { 1 2 840 113554 1 2 1 4 }
  4: { 0 18 18 18 18 18 18 18 18 18 18 }
  5: { 1 2 840 113554 1 2 2 1 }
  6: { 1 2 840 113554 1 2 2 2 }
Signature verified.
#

C.11.4    トラブルシューティングのガイドライン

サンプル・プログラムの実行に関する問題のほとんどは,セキュリティ・サーバのセットアップと管理に関連しています。しかし,サンプル・プログラムを正しく実行できない場合は,次のようにいくつか確認すべき項目があります。

Application Security SDK は Kerberos メカニズムの上層に位置しています。このため,何か不具合が生じた場合,通常は基盤のメカニズムに支障が生じています。サンプル・プログラムは単にエラーを渡しているだけです。たとえば,間違ったパスワードが入力された場合,Kerberos は "Decrypt integrity check failed (復号完全性チェックに失敗しました)" といったメッセージを生成し,これを Application Security SDK に送信します。この場合,サンプル・プログラムは単にエラーを報告し,後始末をして終了します。