JavaScript is required to for searching.
ナビゲーションリンクをスキップ
印刷ビューの終了
Oracle Solaris 11 セキュリティーサービス開発ガイド     Oracle Solaris 11 Information Library (日本語)
search filter icon
search icon

ドキュメントの情報

はじめに

1.  Oracle Solaris の開発者向けセキュリティー機能 (概要)

2.  特権付きアプリケーションの開発

3.  PAM アプリケーションおよび PAM サービスの記述

4.  GSS-API を使用するアプリケーションの記述

5.  GSS-API クライアント例

GSS-API クライアント例の概要

GSS-API クライアント例の構造

GSS-API クライアント例の実行

GSSAPI クライアント例: main() 関数

サーバーとの接続のオープン

サーバーとのセキュリティーコンテキストの確立

サービス名の GSS-API 形式への変換

GSS-API セキュリティーコンテキストの確立

クライアント側におけるその他の GSS-API コンテキスト操作

メッセージのラップと送信

GSS-API クライアントにおける署名ブロックの読み取りと検証

セキュリティーコンテキストの削除

6.  GSS-API サーバー例

7.  SASL を使用するアプリケーションの記述

8.  Oracle Solaris 暗号化フレームワークの紹介

9.  ユーザーレベルの暗号化アプリケーションとプロバイダの記述

10.  Oracle Solaris 鍵管理フレームワークの紹介

A.  C ベース の GSS-API プログラム例

B.  GSS-API リファレンス

C.  OID の指定

D.  SASL ソースコード例

E.  SASL リファレンス

用語集

索引

サーバーとのセキュリティーコンテキストの確立

接続が確立されたあと、call_server() は、次のように関数 client_establish_context() を使ってセキュリティーコンテキストを作成します。

if (client_establish_context(s, service-name, deleg-flag, oid, &context,
                                  &ret-flags) < 0) {
          (void) close(s);
          return -1;
     }

client_establish_context() は次の作業を実行します。

サービス名の GSS-API 形式への変換

client_establish_context() が実行する最初の作業は、gss_import_name() を使ってサービス名の文字列を GSS-API 内部形式に変換することです。

例 5-3 client_establish_context() – サービス名の変換

     /*
     * Import the name into target_name.  Use send_tok to save
     * local variable space.
     */

     send_tok.value = service_name;
     send_tok.length = strlen(service_name) + 1;
     maj_stat = gss_import_name(&min_stat, &send_tok,
                        (gss_OID) GSS_C_NT_HOSTBASED_SERVICE, &target_name);
     if (maj_stat != GSS_S_COMPLETE) {
          display_status("parsing name", maj_stat, min_stat);
          return -1;
     }

gss_import_name() は、サービスの名前を不透明な GSS_API バッファー send_tok として受け取り、その文字列を GSS_API 内部名 target_name に変換します。 send_tok は新しい gss_buffer_desc を宣言せず、領域を節約するために使用されます。 3 番目の引数は gss_OID 型で、send_tok に格納されている名前の形式を示します。 この例は GSS_C_NT_HOSTBASED_SERVICE で、サービスの形式が service@host であることを意味します。 この引数に指定可能なその他の値については、「名前型」を参照してください。

GSS-API セキュリティーコンテキストの確立

サービスの GSS-API 内部形式への変換が完了すると、コンテキストを確立できます。 移植性を最大にするには、コンテキストの確立を常にループとして実行する必要があります。

ループに入る前に、client_establish_context() は、コンテキストと token_ptr パラメータを初期化します。 token_ptr の使用には選択肢があります。token_ptr がポイントできるのは、サーバーに送信するトークンである send_tok、サーバーから返送されてきたトークンである recv_tok のいずれかです。

ループの内側では、次の 2 つの項目が検査されます。

次に、このループの擬似コードを示します。

do gss_init_sec_context() if (コンテキストが作成されなかった場合) エラーを出力して終了する if (状態が「完了」または「処理中」のどちらでもない場合) サービスの名前空間を解放し、エラーを出力して終了する if (サーバーに送信するトークンがある場合、つまりサイズが 0 以外の場合) トークンを送信する if (トークンの送信が失敗した場合) トークンとサービスの名前空間を解放し、 エラーを出力して終了する 送信し終わったトークンの名前空間を解放する if (コンテキストの確立が完了していない場合) サーバーからトークンを受信する while (コンテキストが完了していない)

ループの最初で、gss_init_sec_context() が呼び出されます。この関数の引数は次のとおりです。


注 - クライアントは、コンテキストの起動前に資格を取得する必要はありません。 クライアント側では、資格の管理は GSS-API によって透過的に処理されます。 つまり、この主体のためにこの機構が作成した資格をどのように取得するかを、GSS-API は知っているということです。 このため、アプリケーションは gss_init_sec_context() にデフォルトの資格を渡しています。 しかし、サーバー側では、サーバーアプリケーションはコンテキストを受け入れる前に、サービスの資格を明示的に獲得する必要があります。 「資格の獲得」を参照してください。


connect_to_server() は、コンテキストまたはその一部が存在しており、かつ gss_init_sec_context() が有効な状態を戻していることを確認したあと、gss_init_sec_context() がサーバーに送信すべきトークンを提供しているかどうかを検査します。 トークンが存在しない場合、それはトークンがこれ以上必要ないことを、サーバーが示していると考えられます。 トークンが提供された場合、そのトークンをサーバーに送信する必要があります。 トークンの送信に失敗した場合、トークンとサービスの名前空間を決定できないため、connect_to_server() が終了します。 次のアルゴリズムは、トークンの長さを調べることでトークンの存在の有無を検査しています。

if (send_tok_length != 0) {
     if (send_token(s, &send_tok) < 0) {
          (void) gss_release_buffer(&min_stat, &send_tok);
          (void) gss_release_name(&min_stat, &target_name);
          return -1;
     }
}

send_token() は GSS-API 関数ではなく、ユーザーによって記述される必要があります。 send_token() 関数は、トークンをファイル記述子に書き込みます。send_token() は、正常終了時に 0 を、エラー時に –1 を戻します。 GSS-API 自身はトークンの送受信を行いません。 GSS-API によって作成されたトークンを送受信することは、呼び出し元のアプリケーションの責任です。

コンテキスト確立ループのソースコードを、次に示します。


注 - このソースコード例は、Oracle ダウンロードセンターからダウンロードすることも可能です。 http://www.oracle.com/technetwork/indexes/downloads/sdlc-decommission-333274.html を参照してください。


例 5-4 コンテキスト確立用のループ

/*
 * Perform the context establishment loop.
 *
 * On each pass through the loop, token_ptr points to the token
 * to send to the server (or GSS_C_NO_BUFFER on the first pass).
 * Every generated token is stored in send_tok which is then
 * transmitted to the server; every received token is stored in
 * recv_tok, which token_ptr is then set to, to be processed by
 * the next call to gss_init_sec_context.
 *
 * GSS-API guarantees that send_tok's length will be non-zero
 * if and only if the server is expecting another token from us,
 * and that gss_init_sec_context returns GSS_S_CONTINUE_NEEDED if
 * and only if the server has another token to send us.
 */

token_ptr = GSS_C_NO_BUFFER;
*gss_context = GSS_C_NO_CONTEXT;
1234567890123456789012345678901234567890123456789012345678901234567890123456

do {
    maj_stat =
        gss_init_sec_context(&min_stat, GSS_C_NO_CREDENTIAL, 
        gss_context, target_name, oid, 
        GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | deleg_flag,
        0, NULL,                      /* no channel bindings */
        token_ptr, NULL,              /* ignore mech type */
        &send_tok, ret_flags, NULL);  /* ignore time_rec */
    if (gss_context == NULL){
        printf("Cannot create context\n");
        return GSS_S_NO_CONTEXT;
    }
    if (token_ptr != GSS_C_NO_BUFFER)
        (void) gss_release_buffer(&min_stat, &recv_tok);
    if (maj_stat!=GSS_S_COMPLETE && maj_stat!=GSS_S_CONTINUE_NEEDED) {
        display_status("initializing context", maj_stat, min_stat);
        (void) gss_release_name(&min_stat, &target_name);
        return -1;
    }

    if (send_tok.length != 0){
        fprintf(stdout, "Sending init_sec_context token (size=%ld)...",
            send_tok.length);
        if (send_token(s, &send_tok) < 0) {
            (void) gss_release_buffer(&min_stat, &send_tok);
            (void) gss_release_name(&min_stat, &target_name);
            return -1;
        }
    }
    (void) gss_release_buffer(&min_stat, &send_tok);

    if (maj_stat == GSS_S_CONTINUE_NEEDED) {
        fprintf(stdout, "continue needed...");
        if (recv_token(s, &recv_tok) < 0) {
            (void) gss_release_name(&min_stat, &target_name);
            return -1;
        }
        token_ptr = &recv_tok;
    }
    printf("\n");
} while (maj_stat == GSS_S_CONTINUE_NEEDED);

send_token()recv_token() の動作方法についての詳細は、「その他の GSS-API 関数例」を参照してください。