启用密钥服务因为 Linux 密钥保留服务仍然非常新,在默认情况下 Linux 内核中关闭了这个服务。要想启用密钥服务,必须使用 CONFIG_KEYS=y 选项对内核进行配置。可以在内核编译的 make *config 步骤中 Security options 下面找到这个选项。
清单 4 给出在 Linux 内核中启用密钥服务的配置。
清单 4. 在 Linux 内核中启用密钥服务1
2
3
4
5
6
7
8
9
| ".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 包含 keyctl 命令,可以使用这个命令在密钥上执行各种操作。前面已经列出了 。更多信息参见 Linux 手册页。
创建新的密钥类型学习 Linux 密钥保留服务最容易的方式就是进行实践。下面的示例使用 Linux 密钥保留服务创建一个新类型的密钥。如果还没有 , 现在就执行这个步骤。执行 make 来构建内核模块和用户级程序的二进制代码。这些代码已经在 Linux 内核版本 2.6.20 上测试过了。
示例程序有两个组件:一个内核模块和一个用户空间程序。这个内核模块注册一个新的密钥类型。这个用户空间程序在预定义的 proc-entries 上执行 ioctl,这会导致对内核模块的调用。这个调用会产生一个新的密钥。然后,一个 “bash” shell 返回给用户,它带有新的会话 keyring 和链接到这个 keyring 的新类型的密钥。
因为这个用户空间程序将执行 ioctl,内核模块必须注册 proc_ioctl() 函数来处理 ioctl 请求。所有 ioctl 通信都使用 /proc 接口来进行。清单 5 给出在内核模块中声明的一个新的密钥类型。
清单 5. 声明新的密钥类型1
2
3
4
5
6
7
| 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() 来分配一个新的密钥,从而创建一个会话 keyring。在成功调用 key_alloc() 之后,调用 key_instantiate_and_link() 对密钥进行实例化。在创建并实例化会话 keyring 之后,为用户的会话创建密钥。同样,依次调用 key_alloc() 和 key_instantiate_and_link()。成功完成这些调用之后,用户空间会话就有了一个新密钥。
使用模块创建了新的密钥类型之后,我们来试用一下这个内核模块。模块中的一个基本操作是查看一个进程与哪些 keyring 相关联,以及这些 keyring 包含哪些密钥和其他 keyring。调用 keyctl show 就可以在树结构中显示密钥。清单 6 显示在运行程序之前密钥的状态。
清单 6. 查看进程的 keyring1
2
3
4
| [root@phoenix set.5]# keyctl show
Session Keyring
-3 --alswrv 0 0 keyring: _ses.1976
2 --alswrv 0 0 \_ keyring: _uid.0
|
清单 7 显示插入模块或者卸载模块或用户级程序的命令的输出。这些消息会放在一个系统日志文件中(通常是 /var/log/messages)。
清单 7. 插入内核模块1
2
3
| [root@phoenix set.5]# insmod ./kernel.land/newkey.ko
Loading the module ...
Registered "learning_key"
|
接下来,执行用户级程序。
清单 8. 执行用户级程序1
2
3
4
5
6
7
8
9
| [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. 运行用户级程序之后的密钥状态1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
| [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 中添加了两个文件来管理密钥:/proc/keys 和 /proc/key-users。我们来仔细看看这些文件。
/proc/keys
如果一个进程希望了解它可以查看哪些密钥,它可以通过读取 /proc/keys 获得这些信息。在配置内核时,必须启用这个文件,因为它允许任何用户列出密钥数据库。
清单 10. /proc/keys 文件1
2
3
4
5
6
7
| [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]
|
*Source: linux_kernel_source/security/keys/proc.c:proc_keys_show()
在以上文件中看到的大多数字段来自 include/linux/key.h 中定义的 struct key。可能的标志值见清单 11。
清单 11. struct key 字段可能的标志值1
2
3
4
5
6
| 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 文件1
2
3
4
5
6
| [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 文件的字段1
2
3
4
5
| <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
|
*Source: linux_kernel_source/security/keys/proc.c:proc_key_users_show()
大多数字段是 security/keys/internal.h 中定义的 struct key_user 的字段。
示例程序中演示了所有这些步骤。 |