要約

  • RFC 1509のgss_cred_id_tは、呼び出し元から見て不透明なローカル参照だった。同じ値でも、別の呼び出し元にとっては別の資格証明を指し得た。
  • ハンドルの有効範囲は単一プロセス、子プロセスを含む範囲、同じUIDなどのローカル識別を共有する範囲になり得た。GSS_C_NO_CREDENTIALは無資格を意味せず、既定の資格証明を選ばせる要求になり得た。
  • ハンドル、内部の資格証明、認証された名前、セキュリティコンテキスト、相手へ渡すトークン、アプリケーションの許可判断は別々の証拠である。RFC 1509の可搬性は、この区別を消さずに共通操作だけを定めたことから生まれた。

同じ値を見ても、同じ主体とは言えない

C言語のプログラムでは、二つの値が等しければ同じ対象を指すと考えたくなる。ポインタらしい値ならなおさらだ。だがRFC 1509は、資格証明ハンドルについてその推論を明示的に拒んだ。

gss_cred_id_tは算術型またはポインタ型として実装できる原子的な値だった。ただし、呼び出し元は内部表現を解釈してはならない。さらに仕様は、同じハンドル値が異なる呼び出し元にとって異なる資格証明を示し得ると述べた。

実装は、ハンドルを取得したプロセスだけに有効としてもよい。そのプロセスと子プロセスに広げてもよい。同じUIDのようなローカル識別を共有する複数プロセスに使わせてもよい。したがって値7は、プロセスAではAliceの資格証明を引き、プロセスBではBobのものを引き、別のホストでは何も意味しない可能性がある。

参照を理解する式は、値だけでは閉じない。

呼び出し元 + 実装の時代区分 + ハンドル値 + メカニズム → 資格証明

サービスが再起動して内部スロットを再利用すれば、同じプロセス名と同じ数値でさえ過去との連続性を保証しない。ログが値だけを保存したなら、正確に保存したのは数字であって、主体ではない。

資格証明はAPIの向こう側に残った

資格証明は、あるプリンシパルを表し、そのプリンシパルとして振る舞う能力を与える。しかしアプリケーションが受け取ったのは、秘密鍵やチケット、メカニズム固有の構造そのものではなかった。GSS-APIまたは下位メカニズムが保持する状態へのローカル参照だった。

この分離があるため、RFC 1509はハンドル自体にはセキュリティ上の情報がなく、アプリケーション側で特別に保護する必要もないと説明できた。これは資格証明が安全無害だという意味ではない。値をコピーすれば権限を移せるという意味でもない。重要な制御点は、どの呼び出し元に参照の解決と利用を許すかを決める実装とOSにあった。

言語に依存しないRFC 1508は、その責任をよりはっきり示した。資格証明の取得と利用を適切なプロセスに制限するのは、システム固有の機構とOS機能の仕事だった。あるプリンシパルの資格証明を使えることは、その主体の身元を主張できることに等しい。別プロセスへの移転可能性は、共通APIではなくローカルな仕組みに委ねられた。

ハンドルが秘密でないことと、利用が厳しく制限されることは両立する。図書館の請求記号は公開できても、保管庫から資料を出す窓口は利用者を確認できる。参照記号と引き渡し権限は同じものではない。

「資格証明なし」が既定の主体を呼び出す

GSS_C_NO_CREDENTIALという名前は、この境界を見誤らせやすい。コンテキスト確立時にこれを渡すことは、資格証明を使わないという宣言ではなく、既定の資格証明を選択するよう求める操作になり得た。

RFC 1509は、その既定値をどう設定し、どこまで有効にするかを実装に委ねた。実装経験を取り込んだRFC 2078は、選択の候補を詳しくした。アプリケーションが利用を許された唯一のプリンシパル、既定のネットワークID、既定のローカルIDをネットワークへ写したもの、利用者が設定したIDなどである。適切な既定値を得られない場合には別の失敗結果があった。

これは移植性のための合理的な仕組みだった。アプリケーションは各プラットフォームの鍵保管やアカウント規則を知らずに済む。しかし同じ理由で、監査に必要な主体は環境依存になる。「資格証明を指定しなかった」という記録は、実際に資格証明がなかったことを証明しない。

必要なのは、既定値解決を要求した事実、参照されたポリシー、選ばれたプリンシパル、メカニズム、initiatorかacceptorかという用途、寿命を記録することだ。省略は入力形式であり、認証結果ではない。

コンテキストと接続は別の時計で動く

gss_ctx_id_tにも同じ設計が使われた。これは呼び出し元に相対的な不透明ハンドルで、背後には相手との関係の片側に属する暗号状態などが置かれた。

一方、セキュリティコンテキストはトランスポート接続と同一ではなかった。一つの通信セッションが複数の接続をまたぐことも、一つの通信関係に複数のコンテキストが同時または順次存在することもあった。ソケット番号を知っても、どのGSSコンテキストがどのメッセージを扱ったかは確定しない。

コンテキストが確立したという事実も、その後の各メッセージで完全性や機密性が実際に得られたことを意味しない。アプリケーションは、トークンを正しい相手へ運び、正しいコンテキストへ結び、major statusとメカニズム固有statusを読み、要求したサービスと返されたフラグを比較しなければならなかった。

そして認証後には別の判断が残る。相手が誰かという主張と、その相手に何を許すかという判断と、操作が本当に完了したという観測は別である。共通APIの成功を、業務上の結果まで引き延ばすことはできない。

境界を越えたのは専用のトークンだった

認証トークンもアプリケーションには不透明だったが、ハンドルとは役割が違った。片側のメカニズムがビット列を作り、アプリケーションがそれを運び、相手側のメカニズムが処理する。受信側が理解するためのプロトコル上の経路があった。

ローカルな資格証明ハンドルには、そのような移送契約がない。メモリ表現を他のプロセスやホストへ写しても、資格証明を渡したことにはならない。

後のRFC 2744は、セキュリティコンテキストを本当にプロセス間で移すためにgss_export_sec_contextとgss_import_sec_contextを定めた。エクスポートは元プロセスのコンテキストを無効化し、プロセス間トークンを生成した。同時に有効なインスタンスは一つだけで、インポート可能な相手を同じアカウントやプロセスグループに制限することもできた。

このトークンには鍵などの機密状態が含まれ得るため、移送中の保護と信頼できる宛先が必要だった。ハンドルの値には不要だった保護義務が、実際に状態を運ぶ物には生じた。移転とは、同じ数値を再現することではなく、元を停止し、専用の成果物を作り、受け側で明示的に受理する状態遷移だった。

チャネルバインディングが閉じた範囲

GSS-APIは通信路から独立する設計だったが、チャネルバインディングは意図的な接点を作った。RFC 1509はinitiatorとacceptorのアドレス型・アドレス、そしてアプリケーションデータを与えられるようにした。概念上、メカニズムはそれらを連結して署名し、コンテキスト確立トークンへ結び付けた。相手の入力が違えばGSS_S_BAD_BINDINGSになり得た。

この比較が証明したのは、両端が与えた値の一致である。物理経路、運用主体、法的な帰属まで自動的に証明したわけではない。さらにメカニズムによってはバインディングデータ自体をトークンに含め得たため、RFC 1509は秘密情報を入れないよう注意した。

一つの仕組みが一つの隙間を閉じても、すべての意味を吸収しない。これもまた、証拠を境界ごとに読むという文書全体の姿勢だった。

表示名は人のための投影だった

名前にも同じ慎重さがあった。RFC 1509は、人が読む印字可能な名前と、APIへ渡す内部名を区別した。印字形式はローカル設定や個人の好みに左右され得る。オブジェクト識別子が名前空間を示し、内部表現は異なる名前空間を混同しないための型情報を保持した。

名前の取り込み、表示、比較にはGSS-APIの操作を使う。文字列の一致は同一性の規則ではない。RFC 2744は、取り込んだ内部名を表示しても元の文字列が戻るとは限らないとさらに明記した。DNS形式がX.500形式へ写され、その形で表示されることもあり得た。

画面に同じ文字が出たから同じ主体とは言えない。異なる文字列だから別人とも限らない。必要なのは名前空間、メカニズム、内部比較結果、ローカルアカウントへの対応付け、そしてアプリケーションの許可判断である。表示は運用上重要だが、暗号的な身元と同一ではない。

共通化されたのは問い方だった

RFC 1511はCommon Authentication Technology作業部会の戦略を分業として説明した。セキュリティ専門家が再利用できるメカニズムとサービスを実装し、プロトコル設計者はメカニズムごとの暗号構造を知らなくても共通インターフェースを組み込める。RFC 1508が概念APIを、RFC 1509がC言語の型と呼び出しを定めた。

共通化されたのは、資格証明をどこに置くかという単一の世界規則ではない。参照し、コンテキストを作り、メッセージを保護し、結果を読む方法だった。資格証明の保管、プロセスの利用権、既定の主体、名前変換はローカルに残った。

RFC 2078、RFC 2743、RFC 2744は実装経験を受けて初期仕様を置き換え、操作と説明を増やした。それでも「GSS-APIを使った」だけでは特定の保証を得たことにならないという境界は残った。保証は下位メカニズムと、呼び出し元が要求・確認したサービスに依存した。

薄い標準は弱い標準とは限らない。初期仕様を小さく保ち、将来の実装判断をローカルに置くことで、多様な環境が自発的に参加できた。ただしその代わり、ローカルな決定者が誰かを監査から消してはならない。

仕様書が証明しないもの

資料から確定できるのは、公開された契約と改訂の系譜である。RFC 1509が同一ハンドル値の呼び出し元別解釈を認め、ハンドルと資格証明とトークンを分けたこと、後続RFCが既定値、名前、コンテキスト移送を精密化したことは証明できる。

しかし、特定のライブラリがどの表現を使ったか、あるOSがどの範囲を選んだか、実装が正しかったか、攻撃や事故が起きたかは資料だけでは分からない。Proposed Standardという区分も、普及率や運用品質を示す観測値ではない。

歴史的に重要なのは、仕様がその限界を隠していなかったことだ。小さな値の一致は権限の一致ではない。誰が、どのローカル状態で、何を解決し、どのプリンシパルを主張し、どの操作を許され、何が実際に変わったか。インターネットの共通セキュリティ層は、その長い問いを短い数字で代用しなかった。

Sources