KEYCTL - Linux手册页

时间:2019-08-20 17:58:55  来源:igfitidea点击:

Section: Linux Key Management Calls (2)
更新日期: 2020-06-09

名称

keyctl-操纵内核的密钥管理工具

语法

#include <sys/types.h>
#include <keyutils.h>

long keyctl(int operation, ...)

/* For direct call via syscall(2): */
#include <asm/unistd.h>
#include <linux/keyctl.h>
#include <unistd.h>

long syscall(__NR_keyctl, int operation, __kernel_ulong_t arg2,
             __kernel_ulong_t arg3, __kernel_ulong_t arg4,
             __kernel_ulong_t arg5);

没有为该系统调用提供glibc包装器;请参阅注释。

说明

keyctl()允许用户空间程序执行键操作。

keyctl()执行的操作由操作参数的值确定。这些操作中的每一个都由libkeyutils库(由keyutils包提供)包装为单独的函数(如下所述),以允许编译器检查类型。

允许的操作值为:

KEYCTL_GET_KEYRING_ID(since Linux 2.6.10)
将此过程的特殊密钥ID映射到真实密钥ID。
This operation looks up the special key whose ID is provided in arg2

(cast to
key_serial_t).

If the special key is found,
the ID of the corresponding real key is returned as the function result.
The following values may be specified in
arg2:

KEY_SPEC_THREAD_KEYRING
这指定了调用线程的线程特定的密钥环。参见thread-keyring(7)。
KEY_SPEC_PROCESS_KEYRING
这指定了调用者特定于进程的密钥环。参见process-keyring(7)。
KEY_SPEC_SESSION_KEYRING
这指定了呼叫者的会话特定的密钥环。参见session-keyring(7)。
KEY_SPEC_USER_KEYRING
这指定了呼叫者的特定于UID的密钥环。参见user-keyring(7)。
KEY_SPEC_USER_SESSION_KEYRING
这指定了呼叫者的UID会话密钥环。参见user-session-keyring(7)。
KEY_SPEC_REQKEY_AUTH_KEY(since Linux 2.6.16)
这指定了由request_key(2)创建并传递给它产生的生成密钥的进程的授权密钥。该密钥仅在内核已将授权密钥传递给request-key(8)样式的程序中可用,并且一旦实例化所请求的密钥,该程序便不再可用。参见request_key(2)。
KEY_SPEC_REQUESTOR_KEYRING(since Linux 2.6.29)
这指定了request_key(2)目标密钥环的密钥ID。该密钥环仅在内核已将授权密钥传递给request-key(8)样式的程序中可用,并且一旦实例化所请求的密钥,该密钥环便不再可用。参见request_key(2)。
如果arg2中指定的键不存在,则该行为取决于arg3的值(广播到int)。如果arg3包含一个非零值,则---如果合适的话(例如,在查找用户,用户会话或会话密钥时)-创建一个新密钥,并将其真实密钥ID返回为函数结果。否则,操作将失败,并显示错误ENOKEY。
如果在arg2中指定了有效的密钥ID,并且该密钥存在,则此操作仅返回密钥ID。如果密钥不存在,则调用将失败,并显示错误ENOKEY。
呼叫者必须在钥匙圈上具有搜索权限才能被找到。
参数arg4和arg5被忽略。
libkeyutils通过功能keyctl_get_keyring_ID(3)公开此操作。
KEYCTL_JOIN_SESSION_KEYRING(since Linux 2.6.10)
用新的会话密钥环替换此过程预订的会话密钥环。
如果arg2为NULL,则创建带有描述" _ses"的匿名密钥环,并将该进程作为其会话密钥环订阅该密钥环,从而替换先前的会话密钥环。
Otherwise, arg2

(cast to
char *)

is treated as the description (name) of a keyring,
and the behavior is as follows:

*
如果存在具有匹配描述的密钥环,则该过程将尝试将该密钥环预订为会话密钥环(如果可能);如果不可能,则返回错误。为了订阅密钥环,呼叫者必须对密钥环具有搜索权限。
*
如果不存在具有匹配描述的密钥环,那么将创建具有指定描述的新密钥环,并将该进程作为其会话密钥环订阅该进程。
参数arg3,arg4和arg5被忽略。
libkeyutils通过功能keyctl_join_session_keyring(3)公开此操作。
KEYCTL_UPDATE(since Linux 2.6.10)
更新密钥的数据有效负载。
arg2参数(广播到key_serial_t)指定要更新的密钥的ID。 arg3参数(广播到void *)指向新的有效载荷,而arg4参数(广播到size_t)包含新的有效载荷大小(以字节为单位)。
调用者必须对指定的密钥具有写权限,并且密钥类型必须支持更新。
负实例化的键(请参见KEYCTL_REJECT的描述)可以通过此操作来正实例化。
arg5参数将被忽略。
libkeyutils通过功能keyctl_update(3)公开此操作。
KEYCTL_REVOKE(since Linux 2.6.10)
使用arg2中提供的ID撤消密钥(广播到key_serial_t)。该密钥安排用于垃圾回收;它将不再可找到,并且将无法用于进一步的操作。进一步尝试使用密钥将失败,并显示错误EKEYREVOKED。
调用者必须对密钥具有写或setattr权限。
参数arg3,arg4和arg5被忽略。
libkeyutils通过功能keyctl_revoke(3)公开此操作。
KEYCTL_CHOWN(since Linux 2.6.10)
更改密钥的所有权(用户和组ID)。
arg2参数(广播到key_serial_t)包含密钥ID。 arg3参数(广播到uid_t)包含新的用户ID(如果不应更改用户ID,则为-1)。 arg4参数(广播到gid_t)包含新的组ID(如果不应更改组ID,则为-1)。
密钥必须授予呼叫者setattr权限。
要更改UID或将GID更改为呼叫者不是其成员的组,呼叫者必须具有CAP_SYS_ADMIN功能(请参阅功能(7))。
如果要更改UID,则新用户必须具有足够的配额才能接受密钥。如果更改了UID,配额扣除额将从旧用户移至新用户。
arg5参数将被忽略。
libkeyutils通过功能keyctl_chown(3)公开此操作。
KEYCTL_SETPERM(since Linux 2.6.10)
将arg2参数(提供给key_serial_t)中提供的ID的密钥的权限更改为arg3参数(提供给key_perm_t)中提供的ID的权限。
如果调用者不具有CAP_SYS_ADMIN功能,则它只能更改其拥有的密钥的权限。 (更准确地说:调用者的文件系统UID必须与密钥的UID匹配。)
无论呼叫者的能力如何,密钥都必须向呼叫者授予setattr权限。
The permissions in arg3

specify masks of available operations
for each of the following user categories:

possessor(since Linux 2.6.14)
这是授予拥有密钥的进程的许可(已将其可搜索地附加到该进程的密钥环之一);参见keyrings(7)。
user
这是授予其文件系统UID与密钥的UID匹配的进程的权限。
group
这是授予其文件系统GID或其任何补充GID与密钥的GID匹配的进程的权限。
other
这是授予与用户和组类别不匹配的其他进程的权限。
用户,组和其他类别是互斥的:如果进程与用户类别匹配,它将不会收到在组类别中授予的权限;如果某个进程与用户或组类别匹配,则它将不会收到在其他类别中授予的权限。
所有者类别授予的权限与用户,组或其他类别的授予累积在一起。
Each permission mask is eight bits in size, with only six bits currently used. The available permissions are:
view
此权限允许读取键的属性。
KEYCTL_DESCRIBE操作需要此权限。
每个类别的权限位是KEY_POS_VIEWKEY_USR_VIEW,KEY_GRP_VIEW和KEY_OTH_VIEW。
read
此权限允许读取密钥的有效负载。
KEYCTL_READ操作需要此权限。
每个类别的权限位是KEY_POS_READKEY_USR_READ,KEY_GRP_READ和KEY_OTH_READ。
write
此权限允许更新或实例化密钥的有效负载。对于密钥环,它允许将密钥与密钥环进行链接和取消链接,
KEYCTL_UPDATEKEYCTL_REVOKEKEYCTL_CLEAR,KEYCTL_LINK和KEYCTL_UNLINK操作需要此权限。
每个类别的权限位是KEY_POS_WRITEKEY_USR_WRITE,KEY_GRP_WRITE和KEY_OTH_WRITE。
search
此权限允许搜索钥匙圈并找到钥匙。搜索只能递归到已设置搜索权限的嵌套键环中。
KEYCTL_GET_KEYRING_IDKEYCTL_JOIN_SESSION_KEYRING,KEYCTL_SEARCH和KEYCTL_INVALIDATE操作需要此权限。
每个类别的权限位是KEY_POS_SEARCHKEY_USR_SEARCH,KEY_GRP_SEARCH和KEY_OTH_SEARCH。
link
此权限允许将密钥或密钥环链接到。
KEYCTL_LINK和KEYCTL_SESSION_TO_PARENT操作需要此权限。
每个类别的权限位是KEY_POS_LINKKEY_USR_LINK,KEY_GRP_LINK和KEY_OTH_LINK。
setattr(since Linux 2.6.15).
此权限允许更改密钥的UID,GID和权限掩码。
KEYCTL_REVOKE,KEYCTL_CHOWN和KEYCTL_SETPERM操作需要此权限。
每个类别的权限位是KEY_POS_SETATTRKEY_USR_SETATTR,KEY_GRP_SETATTR和KEY_OTH_SETATTR。
为方便起见,以下宏定义为每个用户类别中所有权限位的掩码:KEY_POS_ALLKEY_USR_ALL,KEY_GRP_ALL和KEY_OTH_ALL。
arg4和arg5参数将被忽略。
libkeyutils通过功能keyctl_setperm(3)公开此操作。
KEYCTL_DESCRIBE(since Linux 2.6.10)
获取描述指定键属性的字符串。
将在arg2中指定要描述的密钥的ID(广播到key_serial_t)。描述性字符串在arg3指向的缓冲区中返回(广播到char *); arg4(广播到size_t)指定该缓冲区的大小(以字节为单位)。
密钥必须授予呼叫者查看权限。
返回的字符串以null终止,并且包含有关密钥的以下信息:
类型; uid; gid;烫发;描述
在上面,类型和描述是字符串,uid和gid是十进制字符串,perm是十六进制权限掩码。描述性字符串以以下格式编写:
%s;%d;%d;%08x;%s
注意:其目的是在未来的内核版本中,描述性字符串应可扩展。特别是,描述字段将不包含分号;应该通过从字符串末尾开始进行反向解析来找到最后一个分号。这允许将来以分号分隔的将来字段插入描述性字符串中。
仅当arg3为非NULL并且指定的缓冲区大小足以接受描述性字符串(包括终止的空字节)时,才尝试写入缓冲区。为了确定缓冲区大小是否太小,请检查操作的返回值是否大于arg4。
arg5参数将被忽略。
libkeyutils通过功能keyctl_describe(3)公开此操作。
KEYCTL_CLEAR
清除密钥环的内容(即取消所有密钥的链接)。
密钥的ID(必须为密钥环类型)在arg2中提供(广播到key_serial_t)。
调用方必须对密钥环具有写权限。
参数arg3,arg4和arg5被忽略。
libkeyutils通过功能keyctl_clear(3)公开此操作。
KEYCTL_LINK(since Linux 2.6.10)
创建从钥匙圈到钥匙的链接。
要链接的密钥在arg2中指定(广播到key_serial_t);密钥环在arg3中指定(广播到key_serial_t)。
如果在密钥环中已经链接了具有相同类型和描述的密钥,则该密钥将从密钥环中移出。
在创建链接之前,内核会检查键环的嵌套并在链接产生循环或键环嵌套太深时返回适当的错误(键环嵌套的限制由内核常量KEYRING_SEARCH_MAX_DEPTH确定,定义为值6,这对于防止递归搜索密钥环时内核堆栈上的溢出是必要的。
调用者必须对要添加的密钥具有链接权限,并且必须对密钥环具有写权限。
参数arg4和arg5被忽略。
libkeyutils通过功能keyctl_link(3)公开此操作。
KEYCTL_UNLINK(since Linux 2.6.10)
取消密钥与密钥环的链接。
要取消链接的密钥的ID在arg2中指定(广播到key_serial_t);要从中取消链接的密钥环的ID在arg3中指定(广播到key_serial_t)。
如果密钥当前未链接到密钥环,则会导致错误。
调用者必须对要从中删除密钥的密钥环具有写许可权。
如果删除了到密钥的最后一个链接,那么该密钥将安排销毁。
参数arg4和arg5被忽略。
libkeyutils通过功能keyctl_unlink(3)公开此操作。
KEYCTL_SEARCH(since Linux 2.6.10)
在密钥环树中搜索密钥,返回其ID,并可以选择将其链接到指定的密钥环。
通过在arg2中传递头部密钥环的ID(广播到key_serial_t)来指定要搜索的树。搜索是广度优先和递归执行的。
arg3和arg4参数指定要搜索的键:arg3(以char *形式显示)包含键类型(一个以空值终止的字符串,最大长度为32个字节,包括终止的空字节)和arg4(以char *)包含键的描述(一个以NULL终止的字符串,最大长度为4096字节,包括终止的null字节)。
源密钥环必须向呼叫者授予搜索权限。执行递归搜索时,将仅搜索授予呼叫者搜索权限的密钥环。只能找到呼叫者具有搜索权限的键。
如果找到了密钥,则将其ID作为函数结果返回。
如果找到了密钥并且arg5(广播到key_serial_t中)为非零值,则在与KEYCTL_LINK相同的约束和规则的约束下,将密钥链接到在arg5中指定ID的密钥环中。如果arg5中指定的目标密钥环已经包含指向具有相同类型和描述的密钥的链接,则该链接将被该操作找到的指向该密钥的链接所取代。
源(arg2)和目标(arg5)密钥环可以是KEYCTL_GET_KEYRING_ID下列出的特殊密钥环ID之一,而不是现有的有效密钥环ID。
libkeyutils通过功能keyctl_search(3)公开此操作。
KEYCTL_READ(since Linux 2.6.10)
读取密钥的有效载荷数据。
在arg2中指定要读取其有效载荷的密钥的ID(广播到key_serial_t)。这可以是现有密钥的ID,也可以是KEYCTL_GET_KEYRING_ID列出的任何特殊密钥ID。
有效负载放置在arg3指向的缓冲区中(广播到char *);该缓冲区的大小必须在arg4中指定(转换为size_t)。
返回的数据将根据密钥类型进行处理以显示。例如,一个密匙环将返回一个key_serial_t条目数组,该数组代表链接到它的所有密匙的ID。用户密钥类型将按原样返回其数据。如果键类型不能实现此功能,则操作将失败,并显示错误EOPNOTSUPP。
如果arg3不为NULL,则将尽可能多的有效负载数据复制到缓冲区中。成功返回时,返回值始终是有效载荷数据的总大小。要确定缓冲区是否足够大,请检查返回值是否小于或等于arg4中提供的值。
从流程密钥环中搜索时,密钥必须授予呼叫者读取权限,或授予呼叫者搜索许可(即,拥有密钥)。
arg5参数将被忽略。
libkeyutils通过功能keyctl_read(3)公开此操作。
KEYCTL_INSTANTIATE(since Linux 2.6.10)
(正)实例化具有指定有效负载的未实例化密钥。
arg2中提供了要实例化的密钥的ID(广播到key_serial_t)。
密钥有效负载在arg3指向的缓冲区中指定(广播到void *);该缓冲区的大小在arg4中指定(转换为size_t)。
如果密钥类型支持有效载荷,则有效载荷可以是NULL指针,并且缓冲区大小可以是0(例如,它是密钥环)。
如果有效载荷数据格式错误或无效,则操作可能会失败。
如果arg5(广播到key_serial_t)不为零,则在与KEYCTL_LINK相同的约束和规则下,实例化的密钥将链接到arg5中指定其ID的密钥环中。
调用方必须具有适当的授权密钥,并且一旦实例化了未实例化的密钥,就将撤销该授权密钥。换句话说,此操作仅可从request-key(8)风格的程序进行。有关未实例化的键和键实例化的说明,请参见request_key(2)。
libkeyutils通过功能keyctl_instantiate(3)公开此操作。
KEYCTL_NEGATE(since Linux 2.6.10)
负实例化一个未实例化的密钥。
此操作等效于调用:
keyctl(KEYCTL_REJECT,arg2,arg3,ENOKEY,arg4);
arg5参数将被忽略。
libkeyutils通过功能keyctl_negate(3)公开此操作。
KEYCTL_SET_REQKEY_KEYRING(since Linux 2.6.13)
设置将为此线程隐式请求的键链接到的默认键环,并返回先前的设置。隐式密钥请求是由内部内核组件发出的,例如在AFS或NFS文件系统上打开文件时可能会发生。从用户空间请求密钥时,设置默认密钥环也将起作用。有关详细信息,请参见request_key(2)。
The arg2

argument (cast to
int)

should contain one of the following values,
to specify the new default keyring:

KEY_REQKEY_DEFL_NO_CHANGE
不要更改默认密钥环。这可用于发现当前的默认密钥环(无需更改)。
KEY_REQKEY_DEFL_DEFAULT
这将选择默认行为,如果有一个,则使用特定于线程的密钥环;如果有一个,则使用特定于进程的密钥环;如果有一个,则使用会话特定的密钥环;否则,请使用与UID有关的会话密钥环,否则用户特定的密钥环。
KEY_REQKEY_DEFL_THREAD_KEYRING
使用特定于线程的密钥环(thread-keyring(7))作为新的默认密钥环。
KEY_REQKEY_DEFL_PROCESS_KEYRING
使用特定于进程的密钥环(process-keyring(7))作为新的默认密钥环。
KEY_REQKEY_DEFL_SESSION_KEYRING
使用特定于会话的密钥环(session-keyring(7))作为新的默认密钥环。
KEY_REQKEY_DEFL_USER_KEYRING
使用特定于UID的密钥环(user-keyring(7))作为新的默认密钥环。
KEY_REQKEY_DEFL_USER_SESSION_KEYRING
使用特定于UID的会话密钥环(user-session-keyring(7))作为新的默认密钥环。
KEY_REQKEY_DEFL_REQUESTOR_KEYRING(since Linux 2.6.29)
使用请求者密钥环。
所有其他值均无效。
参数arg3,arg4和arg5被忽略。
此操作控制的设置由fork(2)的子代继承,并在execve(2)中保留。
libkeyutils通过功能keyctl_set_reqkey_keyring(3)公开此操作。
KEYCTL_SET_TIMEOUT(since Linux 2.6.16)
在密钥上设置超时。
密钥的ID在arg2中指定(广播到key_serial_t)。在arg3中指定从当前时间开始的超时值(以秒为单位)(广播到unsigned int)。超时是根据实时时钟测量的。
将超时值指定为0会清除键上所有现有的超时。
/ proc / keys文件显示每个密钥到期之前的剩余时间。 (这是发现密钥超时的唯一方法。)
调用者必须对密钥具有setattr权限,或者必须具有密钥的实例化授权令牌(请参阅request_key(2))。
超时到期后,该密钥及其任何链接都将被自动垃圾回收。随后的尝试访问密钥的尝试将失败,并显示错误EKEYEXPIRED。
此操作不能用于设置已撤销,已过期或否定实例化的密钥的超时。
参数arg4和arg5被忽略。
libkeyutils通过功能keyctl_set_timeout(3)公开此操作。
KEYCTL_ASSUME_AUTHORITY(since Linux 2.6.16)
假定(或剥离)调用线程实例化密钥的权限。
arg2参数(广播到key_serial_t)指定非零密钥ID来承担授权,或者指定值0来剥离权限。
如果arg2不为零,则它指定要假定其权限的未实例化的ID。然后可以使用KEYCTL_INSTANTIATEKEYCTL_INSTANTIATE_IOV,KEYCTL_REJECT或KEYCTL_NEGATE之一实例化该密钥。一旦实例化了密钥,线程就自动被剥夺了实例化密钥的权限。
仅当调用线程在其密钥环中具有与指定密钥相关联的授权密钥时,才能假定对密钥具有授权。 (换句话说,KEYCTL_ASSUME_AUTHORITY操作仅可从request-key(8)风格的程序使用;有关如何使用此操作的说明,请参见request_key(2)。)调用方必须对授权密钥具有搜索权限。
如果指定的密钥具有匹配的授权密钥,则返回该密钥的ID。可以读取授权密钥(KEYCTL_READ),以获得传递给request_key(2)的标注信息。
如果arg2中给出的ID为0,那么将清除(除掉)当前假定的权限,并返回值0。
KEYCTL_ASSUME_AUTHORITY机制允许诸如request-key(8)之类的程序承担必要的权限,以实例化由于调用request_key(2)而创建的新的未实例化的密钥。有关更多信息,请参见request_key(2)和内核源文件Documentation / security / keys-request-key.txt。
参数arg3,arg4和arg5被忽略。
libkeyutils通过功能keyctl_assume_authority(3)公开此操作。
KEYCTL_GET_SECURITY(since Linux 2.6.26)
获取指定密钥的LSM(Linux安全模块)安全标签。
在arg2中指定要获取其安全标签的密钥的ID(广播到key_serial_t)。安全标签(以空字节终止)将放置在arg3参数指向的缓冲区中(广播到char *);缓冲区的大小必须在arg4中提供(转换为size_t)。
如果将arg3指定为NULL或arg4中指定的缓冲区大小太小,则返回安全标签字符串的完整大小(包括终止的空字节)作为函数结果,并且什么都不会复制到缓冲区。
呼叫者必须对指定键具有查看权限。
返回的安全标签字符串将以适合于有效LSM的形式呈现。例如,对于SELinux,它可能类似于:
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
如果当前没有有效的LSM,则在缓冲区中放置一个空字符串。
arg5参数将被忽略。
libkeyutils通过功能keyctl_get_security(3)和keyctl_get_security_alloc(3)公开此操作。
KEYCTL_SESSION_TO_PARENT(since Linux 2.6.32)
用主叫进程的会话密钥环替换主叫进程的父服务器订阅的主密钥环。
在父进程从内核空间过渡到用户空间的那一点上,将在父进程中替换密钥环。
密钥环必须存在并且必须授予呼叫者链接权限。父进程必须是单线程的,并且具有与此进程相同的有效所有权,并且不能是set-user-ID或set-group-ID。父进程的现有会话密钥环的UID(如果有的话)以及呼叫者会话密钥环的UID与呼叫者的有效UID非常匹配。
事实上,受此操作影响的是父进程,这使得诸如Shell之类的程序可以启动子进程,该子进程使用此操作来更改Shell的会话密钥环。 (这就是keyctl(1)new_session命令的作用。)
参数arg2arg3,arg4和arg5被忽略。
libkeyutils通过功能keyctl_session_to_parent(3)公开此操作。
KEYCTL_REJECT(since Linux 2.6.39)
将密钥标记为负实例化,并在密钥上设置一个到期计时器。此操作提供了较早的KEYCTL_NEGATE操作的功能的超集。
在arg2中指定要否定实例化的键的ID(广播到key_serial_t)。 arg3(广播到unsigned int)参数指定密钥的生存期(以秒为单位)。 arg4参数(广播到unsigned int)指定当搜索击中此键时将返回的错误;通常,这是EKEYREJECTED,EKEYREVOKED或EKEYEXPIRED之一。
如果arg5(广播到key_serial_t)不为零,则在与KEYCTL_LINK相同的约束和规则下,负实例化的密钥将链接到在arg5中指定ID的密钥环中。
呼叫者必须具有适当的授权密钥。换句话说,此操作仅可从request-key(8)风格的程序进行。参见request_key(2)。
调用方必须具有适当的授权密钥,并且一旦实例化了未实例化的密钥,就将撤销该授权密钥。换句话说,此操作仅可从request-key(8)风格的程序进行。有关未实例化的键和键实例化的说明,请参见request_key(2)。
libkeyutils通过功能keyctl_reject(3)公开此操作。
KEYCTL_INSTANTIATE_IOV(since Linux 2.6.39)
使用通过缓冲区向量指定的有效负载实例化未实例化的键。
此操作与KEYCTL_INSTANTIATE相同,但是有效负载数据被指定为iovec结构的数组:
struct iovec {
    void  *iov_base;    /* Starting address of buffer */
    size_t iov_len;     /* Size of buffer (in bytes) */
};
指向有效载荷矢量的指针在arg3中指定(以const struct iovec *形式广播)。向量中的项目数在arg4中指定(以unsigned int形式广播)。
arg2(密钥ID)和arg5(密钥ID)的解释与KEYCTL_INSTANTIATE相同。
libkeyutils通过功能keyctl_instantiate_iov(3)公开此操作。
KEYCTL_INVALIDATE(since Linux 3.5)
将密钥标记为无效。
在arg2中指定要失效的密钥的ID(广播到key_serial_t)。
要使密钥无效,调用者必须对该密钥具有搜索权限。
此操作将密钥标记为无效,并计划立即进行垃圾回收。垃圾回收器从所有密钥环中删除无效的密钥,并在其引用计数达到零时删除该密钥。执行此操作后,即使尚未将其删除,该键也将被所有搜索忽略。
标记为无效的键对于普通的键操作将立即变为不可见,尽管它们在/ proc / keys(标记有" i"标志)中仍然可见,直到被真正删除为止。
参数arg3,arg4和arg5被忽略。
libkeyutils通过功能keyctl_invalidate(3)公开此操作。
KEYCTL_GET_PERSISTENT(since Linux 3.13)
获取指定用户的永久密钥环(persistent-keyring(7))并将其链接到指定的密钥环。
在arg2中指定了用户ID(广播到uid_t)。如果指定值-1,则使用呼叫者的真实用户ID。目标密钥环的ID在arg3中指定(广播到key_serial_t)。
调用者必须在其用户名称空间中具有CAP_SETUID功能,以便获取与调用者的实际或有效用户ID不匹配的用户ID的持久密钥环。
如果调用成功,则将到持久密钥环的链接添加到在arg3中指定了ID的密钥环。
调用方必须对密钥环具有写权限。
如果持久密钥环尚不存在,它将由内核创建。
每次执行KEYCTL_GET_PERSISTENT操作时,持久密钥环将其过期超时重置为以下值:
/proc/sys/kernel/keys/persistent_keyring_expiry
如果达到超时时间,则永久密钥环将被删除,然后销毁所有固定的密钥环。
永久密钥环已在内核版本3.13中添加到Linux。
参数arg4和arg5被忽略。
libkeyutils通过功能keyctl_get_persistent(3)公开此操作。
KEYCTL_DH_COMPUTE(since Linux 4.7)
计算Diffie-Hellman共享密钥或公钥,可以选择将密钥派生函数(KDF)应用于结果。
arg2参数是指向一组参数的指针,该参数包含在Diffie-Hellman计算中使用的三个用户密钥的序列号,并包装为以下形式的结构:
struct keyctl_dh_params {
    int32_t private; /* The local private key */
    int32_t prime; /* The prime, known to both parties */
    int32_t base;  /* The base integer: either a shared
                      generator or the remote public key */
};
在此结构中指定的三个键中的每个键都必须授予调用者读取权限。这些键的有效载荷用于计算Diffie-Hellman结果,如下所示:
基本具有私有模数基数
如果基础是共享生成器,则结果是本地公共密钥。如果基础是远程公共密钥,则结果是共享密钥。
arg3参数(转换为char *)指向用于放置计算结果的缓冲区。该缓冲区的大小在arg4中指定(转换为size_t)。
缓冲区必须足够大以容纳输出数据,否则将返回错误。如果将arg4指定为零,则不使用缓冲区,并且该操作返回所需的最小缓冲区大小(即素数的长度)。
Diffie-Hellman计算可以在用户空间中执行,但是需要一个多精度整数(MPI)库。将实现移入内核可以访问内核MPI实现,并可以访问安全或加速硬件。
由于DH算法用于导出共享密钥,因此在keyctl()系统调用中添加对DH计算的支持被认为是一个很好的选择。它还允许密钥的类型确定哪种DH实现(软件或硬件)合适。
如果arg5参数为NULL,则返回DH结果本身。否则(从Linux 4.12开始),它是指向一个结构的指针,该结构指定要应用的KDF操作的参数:
struct keyctl_kdf_params {
    char *hashname;     /* Hash algorithm name */
    char *otherinfo;    /* SP800-56A OtherInfo */
    __u32 otherinfolen; /* Length of otherinfo data */
    __u32 __spare[8];   /* Reserved */
};
hashname字段是一个以空值结尾的字符串,它指定一个哈希名称(可在内核的crypto API中使用;要查看的哈希列表非常棘手;请参阅"内核Crypto API体系结构"文档,以获取有关如何加密的信息)。哈希名称将被构造,并且您的内核的源代码和配置(有关哪些可用的CRYPTO_ALG_TYPE_SHASH类型的密码和模板可用)将在KDF操作中应用于DH。
otherinfo字段是SP800-56A第5.8.1.2节中描述的OtherInfo数据,并且是特定于算法的。该数据与DH操作的结果串联在一起,并作为KDF操作的输入提供。它的大小在otherinfolen字段中提供,并受在security / keys / internal.h中定义的KEYCTL_KDF_MAX_OI_LEN常数限制为64。
__spare字段当前未使用。在Linux 4.13之前,它一直被忽略(但由于它已复制到内核,因此仍应是用户可寻址的),而从Linux 4.13开始,它应包含零。
KDF实施符合SP800-56A和SP800-108(计数器KDF)。
libkeyutils(从版​​本1.5.10起)通过功能keyctl_dh_compute(3)和keyctl_dh_compute_alloc(3)公开此操作。
KEYCTL_RESTRICT_KEYRING(since Linux 4.12)

Apply a key-linking restriction to the keyring with the ID provided in
arg2

(cast to
key_serial_t).

The caller must have
setattr

permission on the key.
If
arg3

is NULL, any attempt to add a key to the keyring is blocked;
otherwise it contains a pointer to a string with a key type name and
arg4

contains a pointer to string that describes the type-specific restriction.
As of Linux 4.12, only the type "asymmetric" has restrictions defined:

builtin_trusted
仅允许使用由链接到内置密钥环的密钥(" .builtin_trusted_keys")签名的密钥。
builtin_and_secondary_trusted
仅允许由链接到辅助密钥环的密钥(" .secondary_trusted_keys")或扩展名内置密钥环中的密钥签名的密钥,因为后者与前者链接。
key_or_keyring:key
key_or_keyring:key:chain如果key指定类型为" asymmetric"的密钥的ID,则仅允许由该密钥签名的密钥。
如果key指定了密钥环的ID,则仅允许使用由与此密钥环链接的密钥签名的密钥。
如果指定了":chain",则还允许使用由链接到目标密钥环的密钥(即,具有arg2参数中指定ID的密钥环)签名的密钥。
请注意,对于指定的密钥环只能配置一次限制。一旦设置了限制,就不能覆盖它。
参数arg5被忽略。

返回值

对于成功的调用,返回值取决于以下操作:

KEYCTL_GET_KEYRING_ID
请求的密钥环的ID。
KEYCTL_JOIN_SESSION_KEYRING
加入的会话密钥环的ID。
KEYCTL_DESCRIBE
描述的大小(包括终止的空字节),与提供的缓冲区大小无关。
KEYCTL_SEARCH
找到的密钥的ID。
KEYCTL_READ
密钥中可用的数据量,与提供的缓冲区大小无关。
KEYCTL_SET_REQKEY_KEYRING
隐式请求的密钥已链接到的先前默认密钥环的ID(KEY_REQKEY_DEFL_USER_ *中的一个)。
KEYCTL_ASSUME_AUTHORITY
如果给定的ID为0,则为0;如果提供的非零密钥ID,则为与指定密钥匹配的授权密钥的ID。
KEYCTL_GET_SECURITY
LSM安全标签字符串的大小(包括终止的空字节),与提供的缓冲区大小无关。
KEYCTL_GET_PERSISTENT
持久密钥环的ID。
KEYCTL_DH_COMPUTE
复制到缓冲区的字节数;如果arg4为0,则为所需的缓冲区大小。
All other operations
零。

如果出错,则返回-1,并适当设置errno以指示错误。

错误说明

EACCES
不允许执行所请求的操作。
EAGAIN
操作为KEYCTL_DH_COMPUTE,并且加密模块初始化期间发生错误。
EDEADLK
操作是KEYCTL_LINK,请求的链接将导致一个周期。
EDEADLK
操作是KEYCTL_RESTRICT_KEYRING,请求的密钥环限制将导致一个周期。
EDQUOT
通过创建密钥或将其链接到密钥环,将超出呼叫者用户的密钥配额。
EEXIST
操作为KEYCTL_RESTRICT_KEYRING,并且arg2参数中提供的密钥环已设置了限制。
EFAULT
operation

was
KEYCTL_DH_COMPUTE

and one of the following has failed:

*
从用户空间复制arg2参数中提供的struct keyctl_dh_params
*
从用户空间复制非NULL arg5参数中提供的struct keyctl_kdf_params(如果内核支持对DH操作结果执行KDF操作);
*
从用户空间复制结构keyctl_kdf_params的hashname字段所指向的数据;
*
如果otherinfolen字段非零,则从用户空间复制struct keyctl_kdf_params结构的otherinfo字段所指向的数据;
*
将结果复制到用户空间。
EINVAL
操作是KEYCTL_SETPERM,并且在arg3中指定了无效的权限位。
EINVAL
操作为KEYCTL_SEARCH,arg4中的描述大小(包括终止的空字节)超过4096个字节。 arg3(键类型)或arg4(键描述)中指定的字符串(包括终止空字节)的大小超出了限制(分别为32个字节和4096个字节)。
EINVAL(Linux kernels before 4.12)
操作为KEYCTL_DH_COMPUTE,参数arg5为非NULL。
EINVAL
操作为KEYCTL_DH_COMPUTE,并且提供的哈希算法的摘要大小为零。
EINVAL
操作是KEYCTL_DH_COMPUTE,并且提供的缓冲区大小不足以保存结果。提供0作为缓冲区大小以获得最小缓冲区大小。
EINVAL
操作是KEYCTL_DH_COMPUTE,并且arg5参数指向的struct keyctl_kdf_params的结构keyctl_kdf_params的hashname字段中提供的哈希名称太大(该限制是特定于实现的,并且在内核版本之间有所不同,但是对于所有有效的算法名称而言,它都足够大)。
EINVAL
操作是KEYCTL_DH_COMPUTE,arg5参数中提供的struct keyctl_kdf_params的__spare字段包含非零值。
EKEYEXPIRED
找到或指定了过期的密钥。
EKEYREJECTED
找到或指定了拒绝的密钥。
EKEYREVOKED
找到或指定了已撤销的密钥。
ELOOP
操作是KEYCTL_LINK,因此所请求的链接将导致超过钥匙圈的最大嵌套深度。
EMSGSIZE
操作是KEYCTL_DH_COMPUTE,并且缓冲区长度超过了KEYCTL_KDF_MAX_OUTPUT_LEN(当前为1024),或者arg5中传递的struct keyctl_kdf_parms的otherinfolen字段超过了KEYCTL_KDF_MAX_OI_LEN(当前为64)。
ENFILE(Linux kernels before 3.13)
操作为KEYCTL_LINK,并且密钥环已满。 (在Linux 3.13之前,用于存储密钥环链接的可用空间仅限于单个内存页面;从Linux 3.13开始,没有固定的限制。)
ENOENT
操作是KEYCTL_UNLINK,要取消链接的密钥未链接到密钥环。
ENOENT
操作为KEYCTL_DH_COMPUTE,未找到由arg5参数指向的结构keyctl_kdf_params的hashname字段中指定的哈希算法。
ENOENT
操作是KEYCTL_RESTRICT_KEYRING,并且arg3参数中提供的类型不支持设置键链接限制。
ENOKEY
找不到匹配的密钥或指定了无效的密钥。
ENOKEY
在操作中指定了值KEYCTL_GET_KEYRING_ID,arg2中指定的键不存在,而arg3为零(表示如果不存在则不创建键)。
ENOMEM
内核内存分配例程之一在syscall执行期间失败。
ENOTDIR
预期使用密钥环类型的密钥,但是提供了具有不同类型的密钥的ID。
EOPNOTSUPP
操作为KEYCTL_READ,并且密钥类型不支持读取(例如,类型为login)。
EOPNOTSUPP
操作为KEYCTL_UPDATE,并且密钥类型不支持更新。
EOPNOTSUPP
操作为KEYCTL_RESTRICT_KEYRING,arg3参数中提供的类型为"非对称",而arg4中的限制规范中指定的键具有" asymmetric"或" keyring"以外的类型。
EPERM
操作是KEYCTL_GET_PERSISTENT,arg2指定了一个UID,而不是调用线程的实际或有效UID,并且调用者没有CAP_SETUID功能。
EPERM
操作为KEYCTL_SESSION_TO_PARENT,并且操作为:父进程的所有UID(GID)与调用进程的有效UID(GID)不匹配;父级现有会话密钥环的UID或呼叫者会话密钥环的UID与呼叫者的有效UID不匹配;父进程不是单线程的;或父进程是init(1)或内核线程。
ETIMEDOUT
操作为KEYCTL_DH_COMPUTE,并且加密模块的初始化已超时。

版本

该系统调用首次出现在Linux 2.6.10中。

遵循规范

此系统调用是非标准的Linux扩展。

备注

glibc中没有提供此系统调用的包装器。 libkeyutils库中提供了一个包装器。在该库中使用包装器时,请与-lkeyutils链接。但是,您可能不想使用上面的单个操作的描述中提到的各种库函数,而不是直接使用此系统调用。

示例

下面的程序提供了keyutils软件包提供的request-key(8)程序功能的子集。出于参考目的,该程序将各种信息记录在日志文件中。

request_key(2)中所述,request-key(8)程序由描述要实例化的键的命令行参数调用。该示例程序获取并记录这些参数。该程序假定有权实例化所请求的密钥,然后实例化该密钥。

以下shell会话演示了该程序的用法。在会话中,我们编译程序,然后使用它临时替换标准的request-key(8)程序。 (请注意,在某些系统上暂时禁用标准request-key(8)程序可能并不安全。)在安装了示例程序后,我们使用request_key(2)中显示的示例程序来请求密钥。

$ cc -o key_instantiate key_instantiate.c -lkeyutils
$ sudo mv /sbin/request-key /sbin/request-key.backup
$ sudo cp key_instantiate /sbin/request-key
$ ./t_request_key user mykey somepayloaddata
Key ID is 20d035bf
$ sudo mv /sbin/request-key.backup /sbin/request-key

查看此程序创建的日志文件,我们可以看到提供给示例程序的命令行参数:

$ cat /tmp/key_instantiate.log
Time: Mon Nov  7 13:06:47 2016

Command line arguments:
  argv[0]:            /sbin/request-key
  operation:          create
  key_to_instantiate: 20d035bf
  UID:                1000
  GID:                1000
  thread_keyring:     0
  process_keyring:    0
  session_keyring:    256e6a6

Key description:      user;1000;1000;3f010000;mykey
Auth key payload:     somepayloaddata
Destination keyring:  256e6a6
Auth key description: .request_key_auth;1000;1000;0b010000;20d035bf

上面输出的最后几行显示示例程序能够读取:

*
要实例化的密钥的描述,其中包括密钥的名称(mykey);
*
授权密钥的有效负载,包括传递给request_key(2)的数据(somepayloaddata);
*
在对request_key(2)的调用中指定的目标密钥环;和
*
授权密钥的说明,我们可以看到授权密钥的名称与要实例化的密钥的ID(20d035bf)相匹配。

request_key(2)中的示例程序将目标密钥环指定为KEY_SPEC_SESSION_KEYRING。通过检查/ proc / keys的内容,我们可以看到它已被转换为上面日志输出中所示的目标密钥环(0256e6a6)的ID;我们还可以看到新创建的密钥,其名称为mykey,ID为20d035bf。

$ cat /proc/keys | egrep aqmykey|256e6a6aq
0256e6a6 I--Q---  194 perm 3f030000  1000  1000 keyring  _ses: 3
20d035bf I--Q---    1 perm 3f010000  1000  1000 user     mykey: 16

Program source

/* key_instantiate.c */

#include <sys/types.h>
#include <keyutils.h>
#include <time.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>

#ifndef KEY_SPEC_REQUESTOR_KEYRING
#define KEY_SPEC_REQUESTOR_KEYRING      -8
#endif

int
main(int argc, char *argv[])
{
    FILE *fp;
    time_t t;
    char *operation;
    key_serial_t key_to_instantiate, dest_keyring;
    key_serial_t thread_keyring, process_keyring, session_keyring;
    uid_t uid;
    gid_t gid;
    char dbuf[256];
    char auth_key_payload[256];
    int akp_size;       /* Size of auth_key_payload */
    int auth_key;

    fp = fopen("/tmp/key_instantiate.log", "w");
    if (fp == NULL)
        exit(EXIT_FAILURE);

    setbuf(fp, NULL);

    t = time(NULL);
    fprintf(fp, "Time: %s\n", ctime(&t));

    /*
     * The kernel passes a fixed set of arguments to the program
     * that it execs; fetch them.
     */
    operation = argv[1];
    key_to_instantiate = atoi(argv[2]);
    uid = atoi(argv[3]);
    gid = atoi(argv[4]);
    thread_keyring = atoi(argv[5]);
    process_keyring = atoi(argv[6]);
    session_keyring = atoi(argv[7]);

    fprintf(fp, "Command line arguments:\n");
    fprintf(fp, "  argv[0]:            %s\n", argv[0]);
    fprintf(fp, "  operation:          %s\n", operation);
    fprintf(fp, "  key_to_instantiate: %lx\n",
            (long) key_to_instantiate);
    fprintf(fp, "  UID:                %ld\n", (long) uid);
    fprintf(fp, "  GID:                %ld\n", (long) gid);
    fprintf(fp, "  thread_keyring:     %lx\n", (long) thread_keyring);
    fprintf(fp, "  process_keyring:    %lx\n", (long) process_keyring);
    fprintf(fp, "  session_keyring:    %lx\n", (long) session_keyring);
    fprintf(fp, "\n");

    /*
     * Assume the authority to instantiate the key named in argv[2]
     */
    if (keyctl(KEYCTL_ASSUME_AUTHORITY, key_to_instantiate) == -1) {
        fprintf(fp, "KEYCTL_ASSUME_AUTHORITY failed: %s\n",
                strerror(errno));
        exit(EXIT_FAILURE);
    }

    /*
     * Fetch the description of the key that is to be instantiated
     */
    if (keyctl(KEYCTL_DESCRIBE, key_to_instantiate,
                dbuf, sizeof(dbuf)) == -1) {
        fprintf(fp, "KEYCTL_DESCRIBE failed: %s\n", strerror(errno));
        exit(EXIT_FAILURE);
    }

    fprintf(fp, "Key description:      %s\n", dbuf);

    /*
     * Fetch the payload of the authorization key, which is
     * actually the callout data given to request_key()
     */
    akp_size = keyctl(KEYCTL_READ, KEY_SPEC_REQKEY_AUTH_KEY,
                      auth_key_payload, sizeof(auth_key_payload));
    if (akp_size == -1) {
        fprintf(fp, "KEYCTL_READ failed: %s\n", strerror(errno));
        exit(EXIT_FAILURE);
    }

    auth_key_payload[akp_size] = aq##代码##aq;
    fprintf(fp, "Auth key payload:     %s\n", auth_key_payload);

    /*
     * For interest, get the ID of the authorization key and
     * display it.
     */
    auth_key = keyctl(KEYCTL_GET_KEYRING_ID,
            KEY_SPEC_REQKEY_AUTH_KEY);
    if (auth_key == -1) {
        fprintf(fp, "KEYCTL_GET_KEYRING_ID failed: %s\n",
                strerror(errno));
        exit(EXIT_FAILURE);
    }

    fprintf(fp, "Auth key ID:          %lx\n", (long) auth_key);

    /*
     * Fetch key ID for the request_key(2) destination keyring.
     */
    dest_keyring = keyctl(KEYCTL_GET_KEYRING_ID,
                          KEY_SPEC_REQUESTOR_KEYRING);
    if (dest_keyring == -1) {
        fprintf(fp, "KEYCTL_GET_KEYRING_ID failed: %s\n",
                strerror(errno));
        exit(EXIT_FAILURE);
    }

    fprintf(fp, "Destination keyring:  %lx\n", (long) dest_keyring);

    /*
     * Fetch the description of the authorization key. This
     * allows us to see the key type, UID, GID, permissions,
     * and description (name) of the key. Among other things,
     * we will see that the name of the key is a hexadecimal
     * string representing the ID of the key to be instantiated.
     */
    if (keyctl(KEYCTL_DESCRIBE, KEY_SPEC_REQKEY_AUTH_KEY,
                dbuf, sizeof(dbuf)) == -1) {
        fprintf(fp, "KEYCTL_DESCRIBE failed: %s\n", strerror(errno));
        exit(EXIT_FAILURE);
    }

    fprintf(fp, "Auth key description: %s\n", dbuf);

    /*
     * Instantiate the key using the callout data that was supplied
     * in the payload of the authorization key.
     */
    if (keyctl(KEYCTL_INSTANTIATE, key_to_instantiate,
               auth_key_payload, akp_size + 1, dest_keyring) == -1) {
        fprintf(fp, "KEYCTL_INSTANTIATE failed: %s\n",
                strerror(errno));
        exit(EXIT_FAILURE);
    }

    exit(EXIT_SUCCESS);
}

另外参见

keyctl(1),add_key(2),request_key(2),keyctl(3),keyctl_assume_authority(3),keyctl_chown(3),keyctl_clear(3),keyctl_describe(3),keyctl_describe_alloc(3),keyctl_dh_compute(3), keyctl_dh_compute_alloc(3),keyctl_get_keyring_ID(3),keyctl_get_persistent(3),keyctl_get_security(3),keyctl_get_security_alloc(3),keyctl_instantiate(3),keyctl_instantiateate_iov(3),keyctl_session(3),keyctl_session(3),keyctl_session keyctl_negate(3),keyctl_read(3),keyctl_read_alloc(3),keyctl_reject(3),keyctl_revoke(3),keyctl_search(3),keyctl_session_to_parent(3),keyctl_set_reqkey_keyring(3),keyctl_set_time(3),keyctl_set_time keyctl_unlink(3),keyctl_update(3),recursive_key_scan(3),recursive_session_key_scan(3),capabilities(7),凭据(7),keyrings(7),keyutils(7),persistent-keyring(7),process-keyring (7),会话密钥(7),线程密钥(7),用户密钥(7),用户命名空间(7),用户会话密钥(7),请求密钥(8)

内核源文件在Documentation / security / keys /下(或在Linux 4.13之前,在Documentation / security / keys.txt文件中)。

出版信息

这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/