目次


Linux 鍵保存サービス入門

Linux カーネル API を使用して新たな鍵タイプを作成する

Comments

Linux 2.6 カーネルで導入された Linux 鍵保存サービスは、認証データを Linux カーネルにキャッシュすることを主な目的としています。このサービスは、リモート・ファイルシステムなどのカーネル・サービスが、暗号化方式、認証トークン、ドメイン間のユーザー・マッピングなどのセキュリティー関連項目を管理する際に使用することができます。また、このサービスを使うことによって、Linux カーネルから必要な鍵に素早くアクセスしたり、追加、更新、削除などの重要な操作をユーザー空間のプログラムに委譲したりすることも可能になります。

この記事では、Linux 鍵保存サービスについて概説し、その用語を定義します。この記事を読めば、すぐに Linux で鍵を使用できるようになります。またサンプル・コードを使用してカーネル・モジュールで Linux 鍵保存サービスを利用する方法についても説明します。この記事で使用するカーネルのバージョンは 2.6.20 です。

鍵とは?

とは、暗号化データ、認証トークン、あるいはカーネル内で key という構造体 (struct key) によって表されるいくつかの類似した要素、などからなる一群のデータのことです。構造体 key は、Linux カーネル・ソースの include/linux/key.h に定義されています。

リスト 1 に、構造体 key の主要なフィールドをいくつか示します。task_struct、user_struct、および signal_struct は、鍵のサポートを追加するために変更されていることに注意してください。

リスト 1. 構造体 key の主要なフィールド
struct key {
atomic_t                 usage;       /* number of references */
key_serial_t           serial;        /* key serial number */
struct key_type      *type;        /* type of key */
time_t                     expiry;  /* time at which key expires (or 0) */
uid_t                       uid;           /* UID */
gid_t                       gid;           /* GID */
key_perm_t            perm;        /* access permissions */
unsigned short       quotalen;   /* length added to quota */
unsigned short       datalen;     /* payload data length
char                      *description;
union {
unsigned long             value;
void                            *data;
struct keyring_list       *subscriptions;
} payload;                                 /* Actual security data */
....
....
};

鍵の属性

鍵には、次の属性があります。

  • シリアル番号: 32 ビットのゼロでない正の固有の番号
  • タイプ: Linux 鍵保存サービスでは、「ユーザー (user)」および「鍵リング (keyring)」という 2 つの鍵タイプが標準で定義されています。鍵タイプを新たに追加するには、カーネル・サービスで鍵タイプを登録する必要があり、ユーザー空間のプログラムを使って鍵タイプを新規作成することはできません。鍵タイプはカーネル内で key_type という構造体 (struct key_type) で表され、この構造体は include/linux/key.h に定義されています。構造体 key_type の主要なフィールドの一部をリスト 2 に示します。
    リスト 2. key_type の主要なフィールド
    struct key_type {
    const char *name;
    size_t def_datalen;
    
    /* Operations that can be defined for a key_type */
    int (*instantiate)(struct key *key, const void *data, size_t datalen);
    int (*update)(struct key *key, const void *data, size_t datalen);
    int (*match)(const struct key *key, const void *desc);
    void (*revoke)(struct key *key);
    void (*destroy)(struct key *key);
    void (*describe)(const struct key *key, struct seq_file *p);
    long (*read)(const struct key *key, char __user *buffer, size_t buflen);
    ....
    ....
    };

    一連の操作を鍵タイプに関連付けることも可能です。key_type では、次の操作を定義できます。
    • instantiate: 指定のタイプの鍵を新たに作成します。
    • describe: 鍵について説明するテキストを印刷します。
    • match: 鍵の説明に基づいて鍵を検索します。
    • destroy: 鍵に関するすべてのデータをクリアします。
    • request_key: 鍵を検索します。
    • revoke: 鍵データをクリアして、鍵の状態を REVOKED に変更します。
    • read: 鍵データを読み取ります。
    • update: 鍵を変更します。
  • 説明: 鍵について説明する印刷可能なストリング。この属性は、検索操作を実行するときにも使用できます。
  • アクセス制御情報: 所有者 UID、GID、および許可マスクが鍵ごとに用意されています。これらは、ユーザー・レベルのプログラムやカーネル・レベルのプログラムに対し、どのように鍵が応答するかを決定します。鍵にアクセスできるタイプとしては、「所有者 (possessor)」、「ユーザー (user)」、「グループ (group)」、および「その他 (other)」の 4 つがあり、許可マスクはこれら 4 つのタイプそれぞれに 8 ビットずつ割り振ります。その 8 ビットのうち、6 ビットのみが定義されます。許可の種類を次に示します。
    • View: 「所有者」が鍵属性を表示できるようにします。
    • Read: 「所有者」が鍵を読み取り、鍵リングの鍵をリストで表示できるようにします。
    • Write: 「所有者」が鍵または鍵リングのペイロードを変更したり、リンクされた鍵を変更したりできるようにします。
    • Search: 「所有者」が鍵リング内を検索して鍵を見つけられるようにします。
    • Link: 「所有者」が特定の鍵または鍵リングを鍵リングにリンクできるようにします。
    • Set Attribute: 「所有者」が鍵の UID、GID、および許可マスクを設定できるようにします。
  • 有効期限: 鍵の存続期間。鍵の有効期限は無期限にすることもできます。
  • ペイロード: 実際のセキュリティー・データ。struct key_type で定義される操作を使用して、ペイロードをデータによりインスタンス化し、またそのデータを読み出したり修正したりします。カーネルにとっては、ペイロードは単なるデータの塊にすぎません。
  • 状態: 鍵は次のいずれかの状態をとります。
    • UNINSTANTIATED: 鍵は作成されましたが、まだデータに関連付けられていません。
    • INSTANTIATED: 鍵はインスタンス化されて、データに関連付けられました。この状態が完了状態です。
    • NEGATIVE: ユーザー空間への前回の呼び出しが失敗したことを示す一時的な状態です。
    • EXPIRED: 事前定義された存続時間を鍵が超過したことを示します。
    • REVOKED: ユーザー空間のアクションによって鍵がこの状態になりました。
    • DEAD: key_type が登録されていません。

鍵タイプ

定義済みの鍵タイプには、「鍵リング (keyring)」および「ユーザー (user)」の 2 つがあります。

鍵リング」は、他の鍵または鍵リングへの一連のリンクを含む鍵のことです。標準の鍵リングには、次の 6 種類があります。

  1. スレッド固有
  2. プロセス固有
  3. セッション固有
  4. ユーザー固有セッション
  5. ユーザー・デフォルト・セッション
  6. グループ固有 (未実装)

最初の 3 つの鍵リングのみが自動的に検索されます。その場合の検索順序は、上に示した順序と同じです。4 番目のタイプであるユーザー固有セッションの鍵リングは、直接は検索されませんが、通常はセッション固有の鍵リングからリンクされます。PAM などのログイン・プロセスは、別のセッションが作成されるまでユーザー・デフォルト・セッションの鍵リングにバインドされます。

「ユーザー」タイプの鍵は、ユーザー空間のプログラムで扱われるように定義されています。

新たな 3 つの システム・コール

Linux 鍵保存サービスには、ユーザー空間で鍵を扱うための syscall が新たに 3 つ追加されています。最初に add_key について説明します。

key_serial_t add_key(const char *type, const char *desc,
const void *payload, size_t plen,
key_serial_t ring);

add_key システム・コールを使用すると、タイプが type で長さが plen の鍵を作成することができます。鍵の説明は desc で定義され、鍵のペイロードは payload で指し示され、鍵は鍵リンク ring にリンクされます。鍵タイプは、「ユーザー」または「鍵リング」にすることができ、その他の鍵タイプは、カーネル・サービスによって事前にカーネルに登録されていなければなりません。鍵タイプが「鍵リング」の場合は、ペイロードを NULL にして、plen をゼロにします。

次に説明する新規システム・コールは request_key です。

key_serial_t request_key(const char *type, const char *desc,
  const char *callout_info, 
  key_serial_t dest_keyring);

request_key システム・コールにより、プロセス鍵リング内で鍵を検索します。鍵の検索で使用される基本アルゴリズムをリスト 3 に示します。

リスト 3. request_key アルゴリズム
search_into_each_subscribed_keyrings {
if(key is found){
return(found key);
} else {
if(callout_info is NULL){
return(ERROR);
} else {
Execute /sbin/request-key and pass callout_info as argument;
}
}
}

request_key アルゴリズムの仕組みについて詳しくは、Documentation/keys-request-key.txt を参照してください (リンクについては「参考文献」を参照)。

最後に説明するシステム・コール keyctl には、鍵を管理するための多くの機能が用意されています。keyctl に渡される最初の引数に応じて、鍵に対してさまざまな操作を行うことができます。keyctl の操作の一部を以下に示します。

  • KEYCTL_DESCRIBE: 鍵について説明します。
  • KEYCTL_READ: 鍵からペイロード・データを読み取ります。
  • KEYCTL_UPDATE: 指定の鍵を更新します。
  • KEYCTL_LINK: 鍵を鍵リングにリンクします。
  • KEYCTL_UNLINK: 別の鍵リングにリンクされた鍵または鍵リングのリンクを解除します。
  • KEYCTL_JOIN_SESSION_KEYRING: セッション鍵リングを新しいセッション鍵リングで置き換えます。
  • KEYCTL_REVOKE: 鍵を破棄します。
  • KEYCTL_CHOWN: 鍵の所有権を変更します。
  • KEYCTL_SETPERM: 鍵に対する許可マスクを変更します。
  • KEYCTL_CLEAR: 鍵リングの内容をクリアします。
  • KEYCTL_SEARCH: 鍵リング・ツリー内で鍵を検索します。
  • KEYCTL_INSTANTIATE: 部分的に作成された鍵をインスタンス化します。
  • KEYCTL_NEGATE: 部分的に作成された鍵のインスタンス化を無効にします。

keyctl のプロトタイプや keyctl によって実行可能なその他の操作に関する詳細な情報は、Linux の man ページを参照してください。

鍵を管理するためのカーネル API

鍵を管理する上で最も重要な Linux カーネル API の簡単なリストを以下に示します。包括的な情報が必要な場合は、Linux の鍵実装ソース・ファイルをダウンロードして参照してください (「ダウンロード」を参照)。

  • register_key_type は、鍵タイプを新たに定義するときに使用されます。
  • int register_key_type(struct key_type *type) は、同じ名前の鍵タイプがすでに存在する場合に EEXIT を返します。
  • unregister_key_type は、鍵タイプの登録解除に使用されます。
    void unregister_key_type(struct key_type *type);
  • key_put は、鍵を解放します。
    void key_put(struct key *key);
  • request_key は、指定された説明と一致する鍵を検索します。
    struct key *request_key(const struct key_type *type,
    const char *description,
    const char *callout_string);
  • key_alloc は、指定のタイプの鍵を割り当てます。
    struct key *key_alloc(struct key_type *type, const char *desc, 
    uid_t uid, gid_t gid, struct task_struct *ctx,
    key_perm_t perm, unsigned long flags);
  • key_instantiate_and_link は、自動的に鍵をインスタンス化して、それをターゲットの鍵リングとリンクさせます。
    int key_instantiate_and_link(struct key *key,  const void *data,
         size_t datalen, struct key *keyring,
         struct key *instkey);

鍵保存サービスを有効にする

Linux 鍵保存サービスは、まだ非常に新しいサービスであるため、Linux カーネルではデフォルトで無効になっています。鍵保存サービスを有効にするには、CONFIG_KEYS=y オプションを使用してカーネルを構成する必要があります。このオプションは、カーネル・コンパイルの make *config ステップの Security options の中で指定されています。

Linux カーネルで鍵保存サービスを有効にするための構成をリスト 4 に示します。

リスト 4. カーネルで鍵保存サービスを有効にする
".config" file ...
#
# Security options
#
CONFIG_KEYS=y
CONFIG_KEYS_DEBUG_PROC_KEYS=y
CONFIG_SECURITY=y
CONFIG_SECURITY_NETWORK=y
CONFIG_SECURITY_CAPABILITIES=y

鍵のソース・コードは、ディレクトリー linux-2.6.x/security/keys にまとめられています。

次に、keyutils パッケージをダウンロードしてインストールする必要があります。keyutils に含まれている keyctl コマンドを使って、鍵に対してさまざまな操作を実行できます。keyctl 操作の一部は上のリストに示したとおりです。使用方法について詳しくは、Linux の man ページを参照してください。

鍵タイプを新たに作成する

Linux 鍵保存サービスについて学習する最も簡単な方法は、Linux 鍵保存サービスを試してみることです。以下のサンプルでは、Linux 鍵保存サービスを使用して、新しいタイプの鍵を作成しています。まだ試していない場合は、今すぐこのサンプル・プログラムをダウンロードし、make を実行してカーネル・モジュールとユーザー・レベル・プログラムのバイナリーをビルドしてください。このコードは、Linux カーネル・バージョン 2.6.20 でテスト済みです。

このサンプル・プログラムには 2 つのコンポーネント (カーネル・モジュールとユーザー空間プログラム) が含まれています。カーネル・モジュールは、鍵タイプを新たに登録します。ユーザー空間プログラムは実行されると、事前定義された proc-entries に対して ioctl を実行し、その結果カーネル・モジュールが呼び出され、新しい鍵が作成されます。その際、新しいセッション鍵リングと、その鍵リングにリンクされた新しいタイプの鍵とともに、bash シェルがユーザーに返されます。

ユーザー空間プログラムが ioctl を実行するため、ioctl 要求を処理するカーネル・モジュールによって関数 proc_ioctl() が登録されていなければなりません。すべての ioctl 通信は、/proc インターフェースを使用して行われます。リスト 5 では、新しい鍵タイプがカーネル・モジュールで宣言されています。

リスト 5. 新しい鍵タイプを宣言する
struct key_type new_key_type = {
.name = "mykey",
.instantiate = instantiate_key,
.describe = key_desc,
.destroy = key_destroy,
.match = key_match,
};

次に、カーネル・モジュールは、init 関数の中で register_key_type() を呼び出し、新しい鍵 (mykey) を登録します。カーネル・モジュールは、ioctl 要求を受け取ったときに初めて、新しい鍵を割り当てるための key_alloc() を呼び出して、セッション鍵リングを作成します。key_alloc() が正常に呼び出されたら、key_instantiate_and_link() を呼び出して、鍵をインスタンス化してください。セッション鍵リングを作成してインスタンス化したら、ユーザーのセッション用の鍵を作成します。key_alloc() と、その後に続く key_instantiate_and_link() を同じように呼び出します。これらの関数も正常に呼び出すことができれば、新しい鍵がユーザー空間セッションに作成されます。

ここまでのステップはすべて、サンプル・プログラムのデモンストレーションで実行されます。

モジュールを使用する

新しい鍵タイプを作成したら、次にカーネル・モジュールを使用してみます。カーネル・モジュールでの基本操作として、プロセスのサブスクライブ先となる鍵リングと、その鍵リングに含まれる鍵および他の鍵リングを表示します。keyctl show を実行すると、ツリー構造で鍵が表示されます。プログラム実行前の鍵の状態をリスト 6 に示します。

リスト 6. プロセス鍵リングを表示する
[root@phoenix set.5]# keyctl show
Session Keyring
-3 --alswrv      0     0  keyring: _ses.1976
2 --alswrv      0     0   \_ keyring: _uid.0

モジュールを挿入したり、モジュールやユーザー・レベル・プログラムをアンロードしたりするときのコマンドの出力をリスト 7 に示します。出力されたメッセージは、syslog ファイル (通常、/var/log/messages) に記録されます。

リスト 7. カーネル・モジュールを挿入する
[root@phoenix set.5]# insmod ./kernel.land/newkey.ko
Loading the module ...
Registered "learning_key"

次に、ユーザー・レベル・プログラムを実行します。

リスト 8. ユーザー・レベル・プログラムを実行する
[root@phoenix set.5]# ./user.land/session

In /var/log/message, you will see similar output
Installing session keyring:
keyring allocated successfully.
keyring instantiated and linked successfully.
New session keyring installed successfully.
key of new type allocated successfully.
New key type linked to current session.

リスト 9 に実際の鍵を示します。

リスト 9. ユーザー・レベル・プログラムを実行した後の鍵の状態
[root@phoenix set.5]# keyctl show
Session Keyring
-3 --alswrv      0     0  keyring: session.2621
39044642 --alswrv      0     0   \_ mykey: New key type

[root@phoenix set.5]# cat /proc/keys
00000001 I-----     1 perm 1f3f0000     0     0 keyring   _uid_ses.0: 1/4
00000002 I-----     5 perm 1f3f0000     0     0 keyring   _uid.0: empty
0253c622 I--Q--     1 perm 3f3f0000     0     0 mykey   New key type: 0
11a490da I--Q--     2 perm 3f3f0000     0     0 keyring   session.2621: 1/4
13670439 I--Q--     2 perm 1f3f0000     0     0 keyring   _ses.1977: 1/4
159d39b8 I--Q--     5 perm 1f3f0000     0     0 keyring   _ses.1976: 1/4
3a14f259 I--Q--     3 perm 1f3f0000     0     0 keyring   _ses.1978: 1/4
[root@phoenix set.5]# cat /proc/key-users
0:     8 7/7 5/100 136/10000
43:     2 2/2 2/100 56/10000
48:     2 2/2 2/100 56/10000
81:     2 2/2 2/100 56/10000
786:     4 4/4 4/100 113/10000

"keyctl describe <Key>" command gives the description of key.

[root@phoenix set.5]# keyctl describe -3
-3: alswrvalswrv------------     0     0 keyring: session.2621
[root@phoenix set.5]# keyctl describe 39044642
39044642: alswrvalswrv------------     0     0 mykey: New key type
[avinesh@phoenix set.5]$ keyctl search -3 mykey "New key type"
39044642
[root@phoenix set.5]# exit
exit
Now back to our previous state  
[root@phoenix set.5]# keyctl show
Session Keyring
-3 --alswrv      0     0  keyring: _ses.1976
2 --alswrv      0     0   \_ keyring: _uid.0
[root@phoenix set.5]# rmmod ./kernel.land/newkey.ko 
Unloading the module.
Unregistered "learning_key"

鍵に関連する Proc ファイル

/proc に、鍵をモニターするための 2 つのファイル (/proc/keys および /proc/key-users) が追加されます。これらのファイルを詳しく見てみましょう。

/proc/keys

プロセスは表示可能な鍵を認識する必要があるとき、/proc/keys を読み取ることで情報を取得できます。ユーザーが鍵データベースをリスト表示するときに、このファイルを使用するので、このファイルはカーネル構成時に使用可能にされていなければなりません。

リスト 10. /proc/keys ファイル
[root@phoenix set.5]# cat /proc/keys
00000001 I-----  1     perm    1f3f0000      0    0    keyring    _uid_ses.0 : 1/4
00000002 I-----  5     perm    1f3f0000      0    0    keyring    _uid.0     : empty
13670439 I--Q--  2     perm    1f3f0000      0    0    keyring    _ses.1977  : 1/4
159d39b8 I--Q--  6     perm    1f3f0000      0    0    keyring    _ses.1976  : 1/4
3a14f259 I--Q--  3     perm    1f3f0000      0    0    keyring    _ses.1978  : 1/4
[Serial][Flags][Usage][Expiry][Permissions][UID][GID][TypeName][Description] :[Summary]

*ソース: linux_kernel_source/security/keys/proc.c:proc_keys_show()

上記ファイルのフィールドは、大部分 include/linux/key.h に定義された struct key からのものです。使用可能なフラグ値をリスト 11 に示します。

リスト 11. struct key フィールドの使用可能なフラグ値
I        Instantiated
R        Revoked
D        Dead
Q        Contributes to user's quota
U        Under construction by callback to user-space
N        Negative key

/proc/key-users

リスト 12 に /proc/key-users ファイルを示します。

リスト 12. /proc/key-users ファイル
[root@phoenix set.5]# cat /proc/key-users
0:     6 5/5 3/100 90/10000
43:     2 2/2 2/100 56/10000
48:     2 2/2 2/100 56/10000
81:     2 2/2 2/100 56/10000
786:     4 4/4 4/100 113/10000

リスト 13 に示すフィールドは、各行に順番に対応しています。

リスト 13. /proc/key-users ファイルのフィールド
<UID>                     User ID
<usage>                 Usage count
<inst>/<keys>      Total number of keys and number instantiated
<keys>/<max>     Key count quota
<bytes><max>     Key size quota

*ソース: linux_kernel_source/security/keys/proc.c:proc_key_users_show()

これらのフィールドは、大部分 security/keys/internal.h に定義された struct key_user のフィールドです。

まとめ

Linux 鍵保存サービスは、Linux カーネルによる高速アクセスのためのセキュリティー関連情報を保持するために導入された新しいメカニズムです。Linux 鍵保存サービスは、まだ初期段階にあり、やっと広く認められ始めたところです。OpenAFS では、プロセス認証グループ (PAG) を実装するために Linux 鍵保存サービスを使用しており、NFSv4 や MIT Kerberos でも同様に使用されています。Linux 鍵保存サービスは、まだ開発途上にあり、今後も修正されたり、機能強化されたりする可能性があります。


ダウンロード可能なリソース


関連トピック


コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Linux
ArticleID=251500
ArticleTitle=Linux 鍵保存サービス入門
publish-date=04112007