KEYRINGS - Linux手册页
Linux程序员手册 第7部分
更新日期: 2020-08-13
名称
密钥环-内核内密钥管理和保留功能
说明
Linux密钥管理工具主要是各种内核组件在内核中保留或缓存安全数据,身份验证密钥,加密密钥和其他数据的一种方式。
提供系统调用接口,以便用户空间程序可以管理那些对象,也可以将其用于自己的目的。请参阅add_key(2),request_key(2)和keyctl(2)。
提供了一个库和一些用户空间实用程序以允许访问该设施。有关更多信息,请参见keyctl(1),keyctl(3)和keyutils(7)。
Keys
密钥具有以下属性:
- Serial number (ID)
这是唯一的整数句柄,在系统调用中通过该句柄引用键。有时将序列号同义地称为密钥ID。通过编程,密钥序列号使用key_serial_t类型表示。
- Type
密钥的类型定义了密钥中可以保存哪种数据,如何解析密钥的建议内容以及如何使用有效负载。
有许多通用类型可用,以及由特定内核组件定义的一些专家类型。
- Description (name)
键说明是一个可打印的字符串,用作键的搜索项(与键类型结合使用)以及显示名称。在搜索过程中,描述可能会部分匹配或完全匹配。
- Payload (data)
有效负载是密钥的实际内容。通常在创建密钥时进行设置,但是如果内核在请求密钥时还不知道该密钥,则内核有可能向上调用用户空间以完成密钥的实例化。有关更多详细信息,请参见request_key(2)。
如果密钥类型支持密钥的有效负载,并且已将适当的权限授予调用者,则可以读取和更新密钥的有效负载。
- Access rights
就像文件一样,每个密钥都有一个拥有的用户ID,拥有的组ID和安全标签。每个键也具有一组权限,尽管除了普通的UNIX文件外,还具有更多的权限,并且除了普通的用户,组和其他用户之外,还有一个附加的类别(拥有者)(请参见下面的所有权)。
请注意,密钥受配额控制,因为它们需要不可交换的内核内存。拥有的用户ID指定要借记其配额的用户。
- Expiration time
每个密钥可以设置一个到期时间。达到该时间后,该密钥将标记为已过期,并且访问失败,并显示错误EKEYEXPIRED。如果未删除,更新或替换,则在设置的时间后,将自动删除过期的密钥(收集垃圾)以及所有指向它的链接,并且尝试访问该密钥失败,并显示错误ENOKEY。
- Reference count
每个键都有一个参考计数。密钥由密钥环,当前活动的用户以及进程的凭据引用。当引用计数达到零时,将调度该键进行垃圾回收。
Key types
内核提供了几种基本类型的密钥:
- keyring
密钥环是特殊密钥,用于存储指向其他密钥(包括其他密钥环)的一组链接,类似于包含指向文件链接的目录。密钥环的主要目的是防止垃圾回收其他密钥,因为没有东西引用它们。
具有以句点(aq.aq)开头的描述(名称)的密钥环保留给实现。
- user
这是通用密钥类型。密钥完全保留在内核内存中。有效载荷可以由用户空间应用程序读取和更新。
此类密钥的有效载荷是最多32,767字节的任意数据的blob。
该描述可以是任何有效的字符串,尽管最好以冒号分隔的前缀开头,该前缀代表密钥所关注的服务(例如,afs:mykey)。
- logon(since Linux 3.3)
此密钥类型与用户基本相同,但不提供读取功能(即keyctl(2)KEYCTL_READ操作),这意味着密钥有效载荷永远不会在用户空间中可见。这适用于存储用户空间不可读的用户名-密码对。
登录密钥的描述必须以非空的冒号分隔的前缀开头,其目的是识别密钥所属的服务。 (请注意,这与用户类型的键不同,在用户类型的键中建议添加前缀但不强制使用。)
- big_key(since Linux 3.13)
此密钥类型与用户密钥类型相似,但是它可以容纳最大1 MiB的有效负载。此密钥类型可用于保持Kerberos票证高速缓存之类的目的。
如果数据大小超出了将数据存储在文件系统中的开销,则可以将有效负载数据存储在tmpfs文件系统中,而不是存储在内核内存中。 (将数据存储在文件系统中需要在内核中分配文件系统结构。这些结构的大小决定了使用tmpfs存储方法的大小阈值。)从Linux 4.8开始,有效载荷数据在存储在tmpfs中时会被加密,从而防止将其未加密地写入交换空间。
还可以使用更多专门的密钥类型,但是这里不讨论它们,因为它们不适合正常的用户空间使用。
以句点(aq.aq)开头的键类型名称保留给实现。
Keyrings
如前所述,密钥环是一种特殊类型的密钥,其中包含指向其他密钥的链接(可能包括其他密钥环)。密钥可以通过多个密钥环链接到。密钥环可被视为类似于UNIX目录,其中每个目录都包含一组指向文件的硬链接。
各种操作(系统调用)只能应用于密钥环:
- Adding
可以通过创建密钥的系统调用将密钥添加到密钥环。这样可以防止在系统调用释放对密钥的最后引用时立即删除新密钥。
- Linking
可以将链接添加到指向已知密钥的密钥环,前提是这不会创建自引用循环。
- Unlinking
可以从钥匙圈中删除链接。当最后一个指向键的链接被删除时,该键将被安排为由垃圾回收器删除。
- Clearing
所有链接都可以从钥匙圈中删除。
- Searching
密匙环可被视为树或子树的根,其中密匙环形成分支而非密匙叶。可以在该树中搜索与特定类型和描述匹配的密钥。
有关更多信息,请参见keyctl_clear(3),keyctl_link(3),keyctl_search(3)和keyctl_unlink(3)。
Anchoring keys
为防止密钥被垃圾回收,当内核不对其进行主动使用时,必须对其进行锚定以保持其引用计数增加。
密钥环用于锚定其他密钥:每个链接都是密钥上的引用。请注意,密钥环本身只是密钥,并且还必须遵循相同的锚定要求,以防止被垃圾回收。
内核提供了许多锚键环。请注意,其中某些钥匙圈仅在首次访问时才会创建。
- Process keyrings
流程凭证本身使用特定的语义引用密钥环。只要存在凭据集(通常只要存在该过程),就会固定这些密钥环。
共有三个具有不同继承/共享规则的密钥环:session-keyring(7)(由所有子进程继承和共享),process-keyring(7)(由进程中的所有线程共享)和thread-keyring( 7)(特定于特定线程)。
作为使用实际密钥环ID的替代方法,在对add_key(2),keyctl(2)和request_key(2)的调用中,特殊密钥环值KEY_SPEC_SESSION_KEYRING,KEY_SPEC_PROCESS_KEYRING和KEY_SPEC_THREAD_KEYRING可以用于引用调用者自己的实例这些钥匙扣。
- User keyrings
内核已知的每个UID都有一条包含两个密钥环的记录:user-keyring(7)和user-session-keyring(7)。只要内核中的UID记录存在,它们就存在。
作为使用实际密钥环ID的替代方法,在对add_key(2),keyctl(2)和request_key(2)的调用中,特殊密钥环值KEY_SPEC_USER_KEYRING和KEY_SPEC_USER_SESSION_KEYRING可用于引用调用者自己的这些密钥环实例。
启动新的登录会话时,通过pam_keyinit(8)将指向用户密钥环的链接放置在新的会话密钥环中。
- Persistent keyrings
对于系统已知的每个UID,都有一个persistent-keyring(7)。它可能会持续到前面提到的UID记录的寿命之外,但是设置了到期时间,以便在设置的时间后自动清除它。持久密钥环允许例如cron(8)脚本使用用户注销后保留在持久密钥环中的凭据。
请注意,每次请求持久密钥时,都会重置持久密钥环的到期时间。
- Special keyrings
内核拥有一些特殊的密钥环,可以为特殊目的锚定密钥。例如,系统密钥环用于保存用于模块签名验证的加密密钥。
这些特殊的密钥环通常是封闭的,以便用户空间直接进行更改。
到目前为止,尚未实现用于存储与内核已知的每个GID相关联的密钥的最初计划的"组密钥环"。但是,已为此密钥环定义了常量KEY_SPEC_GROUP_KEYRING。
Possession
拥有概念对于理解密钥环安全模型很重要。线程是否拥有密钥由以下规则确定:
- (1)
在以下所有规则中,将忽略任何未授予呼叫者搜索权限的密钥或密钥环。
- (2)
线程直接拥有其会话密钥(7),进程密钥(7)和线程密钥(7),因为这些密钥环由其凭据引用。
- (3)
如果拥有钥匙圈,那么它链接到的任何钥匙也都拥有。
- (4)
如果密钥环链接到的任何密钥本身就是密钥环,则规则(3)递归适用。
- (5)
如果从内核调用了一个过程以实例化一个密钥(请参阅request_key(2)),则它也像规则(1)一样拥有请求者的密钥环,就好像它是请求者一样。
注意,拥有不是密钥的基本属性,而是每次需要密钥时都必须计算。
拥有权旨在允许从用户外壳运行的设置用户ID程序访问用户的键。向密钥所有者授予许可权,同时拒绝密钥所有者和密钥组许可,则可以防止基于UID和GID匹配访问密钥。
当创建会话密钥环时,pam_keyinit(8)将一个链接添加到user-keyring(7),从而使用户密钥环及其包含的任何内容默认都具有。
Access rights
每个密钥具有以下与安全性相关的属性:
- *
拥有的用户ID
- *
允许访问密钥的组的ID
- *
安全标签
- *
权限掩码
权限掩码包含四组权限。前三套是互斥的。一项访问检查将仅执行一次。按照优先级从高到低的顺序,这三组分别是:
- user
如果密钥的用户ID与调用者的文件系统用户ID相匹配,则该集合指定授予的权限。
- group
如果用户ID不匹配且密钥的组ID与调用者的文件系统GID或调用者的补充组ID之一匹配,则该集合指定授予的权限。
- other
该集合指定了密钥的用户ID和组ID都不匹配时授予的权限。
第四组权利是:
- possessor
该集合指定如果确定调用者拥有密钥,则授予的权限。
密钥的完整权限集是适用的前三组中的哪一个加和(如果拥有密钥则适用第四组)。
可以在四个掩码中的每个掩码中授予的权限集如下:
- view
可以读取密钥的属性。这包括类型,描述和访问权限(不包括安全标签)。
- read
对于密钥:可以读取密钥的有效载荷。对于密钥环:可以读取该密钥环链接到的序列号(密钥)列表。
- write
密钥的有效载荷可以被更新并且密钥可以被撤销。对于密钥环,可以将链接添加到密钥环或从密钥环中删除,并且可以完全清除密钥环(删除所有链接),
- search
对于密钥(或密钥环):可以通过搜索找到密钥。对于密钥环:可以搜索由密钥环链接的密钥和密钥环。
- link
可以从钥匙圈到钥匙创建链接。创建密钥时所建立的密钥的初始链接不需要此权限。
- setattr
可以更改密钥的所有权详细信息和安全标签,可以设置密钥的到期时间,并且可以撤销密钥。
除了访问权限,如果其策略要求,任何活动的Linux安全模块(LSM)都可能会阻止访问密钥。 LSM可以为密钥提供安全标签或其他属性;可通过keyctl_get_security(3)检索此标签。
有关更多信息,请参见keyctl_chown(3),keyctl_describe(3),keyctl_get_security(3),keyctl_setperm(3)和selinux(8)。
Searching for keys
Linux密钥管理工具的关键功能之一是能够找到进程保留的密钥。 request_key(2)系统调用是用户空间应用程序查找密钥的主要访问点。 (在内部,内核有一些相似的东西可供使用键的内部组件使用。)
搜索算法的工作原理如下:
- (1)
进程密钥环按以下顺序搜索:线程thread-keyring(7)(如果存在),process-keyring(7)(如果存在),然后session-keyring(7)(如果存在)或用户- session-keyring(7)(如果存在)。
- (2)
如果调用方是由request_key(2)上调用机制调用的进程,则还将搜索request_key(2)的原始调用方的密钥环。
- (3)
密钥环树的搜索按广度优先顺序进行:首先在每个密钥环中搜索匹配项,然后搜索该密钥环所引用的密钥环。
- (4)
如果找到有效的匹配密钥,则搜索将终止并返回该密钥。
- (5)
如果找到带有错误状态的匹配键,则会记录该错误状态并继续搜索。
- (6)
如果找不到有效的匹配密钥,则返回第一个记录的错误状态;否则,返回错误状态。否则,将返回ENOKEY错误。
还可以搜索特定的钥匙圈,在这种情况下,仅适用步骤(3)至(6)。
有关更多信息,请参见request_key(2)和keyctl_search(3)。
On-demand key creation
如果找不到密钥,则在给定callout_info参数的情况下,request_key(2)将创建一个新密钥,然后向上调用用户空间以实例化该密钥。这样就可以根据需要创建密钥。
通常,这将涉及内核创建一个新进程,该进程执行request-key(8)程序,然后该程序将根据其配置执行适当的处理程序。
向处理程序传递一个特殊的授权密钥,该密钥允许它并且只有它才能实例化新密钥。这也用于允许由处理程序执行的搜索也搜索请求者的密钥环。
有关更多信息,请参见request_key(2),keyctl_assume_authority(3),keyctl_instantiate(3),keyctl_negate(3),keyctl_reject(3),request-key(8)和request-key.conf(5)。
/proc files
内核提供各种/ proc文件,这些文件公开有关密钥的信息或定义密钥使用限制。
- /proc/keys(since Linux 2.6.10)
该文件公开了读取线程具有查看权限的键列表,并提供了有关每个键的各种信息。线程不需要拥有密钥,该密钥在此文件中可见。
列表中包括的唯一键是那些授予阅读过程查看权限的键(无论它是否拥有它们)。 LSM安全检查仍在执行,并且可能会过滤掉该进程无权查看的其他密钥。
下面是一个可能在此文件中看到的数据示例(其列编号为便于参考)如下:
(1) (2) (3)(4) (5) (6) (7) (8) (9) 009a2028 I--Q--- 1 perm 3f010000 1000 1000 user krb_ccache:primary: 12 1806c4ba I--Q--- 1 perm 3f010000 1000 1000 keyring _pid: 2 25d3a08f I--Q--- 1 perm 1f3f0000 1000 65534 keyring _uid_ses.1000: 1 28576bd8 I--Q--- 3 perm 3f010000 1000 1000 keyring _krb: 1 2c546d21 I--Q--- 190 perm 3f030000 1000 1000 keyring _ses: 2 30a4e0be I------ 4 2d 1f030000 1000 65534 keyring _persistent.1000: 1 32100fab I--Q--- 4 perm 1f3f0000 1000 65534 keyring _uid.1000: 2 32a387ea I--Q--- 1 perm 3f010000 1000 1000 keyring _pid: 2 3ce56aea I--Q--- 5 perm 3f030000 1000 1000 keyring _ses: 1
该文件每一行中显示的字段如下:
- ID (1)
密钥的ID(序列号),以十六进制表示。
- Flags (2)
一组描述密钥状态的标志:
- I
密钥已实例化。
- R
密钥已被撤消。
- D
密钥已失效(即密钥类型尚未注册)。 (在垃圾回收期间,密钥可能会短暂处于此状态。)
- Q
密钥有助于用户的配额。
- U
密钥是通过回调用户空间来构造的。请参阅request-key(2)。
- N
密钥被否定化。
- i
密钥已失效。
- Usage (3)
这是固定该密钥的内核凭证结构的数量的计数(大约:引用该密钥的线程和打开文件引用的数量)。
- Timeout (4)
密钥到期之前的时间,以人类可读的形式表示(周,日,小时,分钟和秒)。这里的字符串perm表示密钥是永久性的(无超时)。字符串expd表示密钥已经过期,但是尚未被垃圾回收。
- Permissions (5)
密钥权限,表示为四个十六进制字节,从左到右包含所有者,用户,组和其他权限。在每个字节内,权限位如下:
- 0x01
视图
- Ox02
读
- 0x04
写
- 0x08
搜索
- 0x10
链接
- 0x20
定居者
- UID (6)
密钥所有者的用户标识。
- GID (7)
密钥的组ID。这里的值-1表示密钥没有组ID;在某些情况下,内核创建的密钥可能会发生这种情况。
- Type (8)
密钥类型(用户,密钥环等)
- Description (9)
密钥描述(名称)。该字段包含有关密钥的描述性信息。对于大多数键类型,它具有以下形式
名称[:Extra-info]
- The
name
subfield is the key's description (name).
The optional
extra-infofield provides some further information about the key.
The information that appears here depends on the key type, as follows:- userand logon
密钥有效负载的字节大小(以十进制表示)。
- keyring
链接到密钥环的密钥数;如果没有链接到密钥环的字符串,则为空字符串。
- big_key
有效载荷大小(以字节为单位),如果关键有效载荷超过阈值,则后跟字符串[file],这意味着有效载荷存储在(可交换的)tmpfs(5)文件系统中;否则,字符串[buff]指示密钥足够小,可以驻留在内核内存中。
对于.request_key_auth密钥类型(授权密钥;请参阅request_key(2)),描述字段的格式如下例所示:
密钥:c9a9b19 pid:28880 ci:10
三个子字段如下:
- key
在请求程序中实例化的密钥的十六进制ID。
- pid
请求程序的PID。
- ci
用来实例化所请求密钥的标注数据的长度(即与授权密钥关联的有效负载的长度)。
- /proc/key-users(since Linux 2.6.10)
该文件列出了在系统上至少具有一个密钥的每个用户ID的各种信息。下面是一个可能在此文件中看到的数据示例:
0: 10 9/9 2/1000000 22/25000000 42: 9 9/9 8/200 106/20000 1000: 11 11/11 10/200 271/20000
每行中显示的字段如下:
- uid
用户ID。
- usage
这是用于记录关键用户的内核结构的内核内部使用计数。
- nkeys/nikeys
用户拥有的密钥总数,以及已实例化的那些密钥的数量。
- qnkeys/maxkeys
用户拥有的密钥数量,以及用户可能拥有的最大密钥数量。
- qnbytes/maxbytes
该用户拥有的密钥的有效载荷中消耗的字节数,以及该用户的密钥有效载荷中的字节数上限。
- /proc/sys/kernel/keys/gc_delay(since Linux 2.6.32)
此文件中的值指定间隔(以秒为单位),在此间隔之后将对垃圾桶中已撤销和过期的密钥进行回收。设置此间隔的目的是,在一个时间窗口内,用户空间可以看到指示密钥发生了什么的错误(分别为EKEYREVOKED和EKEYEXPIRED)。
此文件的默认值为300(即5分钟)。
- /proc/sys/kernel/keys/persistent_keyring_expiry(since Linux 3.13)
该文件定义了一个时间间隔(以秒为单位),每次访问密钥环时(通过keyctl_get_persistent(3)或keyctl(2)KEYCTL_GET_PERSISTENT操作),都会重置永久密钥环的到期计时器。
该文件的默认值为259200(即3天)。
以下文件(特权进程可写)用于对可存储在密钥有效负载中的密钥数和数据字节数实施配额:
- /proc/sys/kernel/keys/maxbytes(since Linux 2.6.26)
这是非root用户可以在用户拥有的密钥的有效负载中保留的最大数据字节数。
该文件的默认值为20,000。
- /proc/sys/kernel/keys/maxkeys(since Linux 2.6.26)
这是非root用户可能拥有的最大密钥数。
该文件的默认值为200。
- /proc/sys/kernel/keys/root_maxbytes(since Linux 2.6.26)
这是root用户(root用户名称空间中的UID 0)可以在root拥有的键的有效负载中保留的最大数据字节数。
该文件的默认值为25,000,000(Linux 3.17之前为20,000)。
- /proc/sys/kernel/keys/root_maxkeys(since Linux 2.6.26)
这是root用户(root用户名称空间中的UID 0)可以拥有的最大密钥数。
该文件的默认值为1,000,000(Linux 3.17之前为200)。
关于密钥环,请注意,密钥环中的每个链接消耗4个字节的密钥环有效载荷。
Users
Linux密钥管理工具具有许多用户和用法,但不仅限于已经存在的用户和用法。
此功能的内核用户包括:
- Network filesystems - DNS
内核使用密钥提供的上行调用机制来上行调用用户空间以进行DNS查找,然后缓存结果。
- AF_RXRPC and kAFS - Authentication
AF_RXRPC网络协议和内核AFS文件系统使用密钥存储进行安全或加密流量所需的票证。然后通过AF_RXRPC上的网络操作和kAFS上的文件系统操作来查找这些文件。
- NFS - User ID mapping
NFS文件系统使用密钥来存储外部用户ID到本地用户ID的映射。
- CIFS - Password
CIFS文件系统使用密钥存储用于访问远程共享的密码。
- Module verification
可以进行内核构建过程以对模块进行密码签名。然后在加载模块时检查该签名。
此功能的用户空间用户包括:
- Kerberos key storage
MIT Kerberos 5工具(libkrb5)可以使用密钥来存储身份验证令牌,可以使该令牌在用户最后一次使用它们后的指定时间自动清除,但是在此之前,它们会在用户注销后保持挂起状态,以便cron(8)脚本可以使用它们。
另外参见
keyctl(1),add_key(2),keyctl(2),request_key(2),keyctl(3),keyutils(7),持久密钥(7),进程密钥(7),会话密钥(7) ,线程密钥(7),用户密钥(7),用户会话密钥(7),pam_keyinit(8),请求密钥(8)
内核源文件Documentation / crypto / asymmetric-keys.txt和Documentation / security / keys下(或在Linux 4.13之前的文件Documentation / security / keys.txt中)。
出版信息
这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/。