요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
============================
Kernel Key Retention Service
============================
This service allows cryptographic keys, authentication tokens, cross-domain
user mappings, and similar to be cached in the kernel for the use of
filesystems and other kernel services.
Keyrings are permitted; these are a special type of key that can hold links to
other keys. Processes each have three standard keyring subscriptions that a
kernel service can search for relevant keys.
The key service can be configured on by enabling:
"Security options"/"Enable access key retention support" (CONFIG_KEYS)
This document has the following sections:
.. contents:: :local:
Key Overview
============
In this context, keys represent units of cryptographic data, authentication
tokens, keyrings, etc.. These are represented in the kernel by struct key.
Each key has a number of attributes:
- A serial number.
- A type.
- A description (for matching a key in a search).
- Access control information.
- An expiry time.
- A payload.
- State.
* Each key is issued a serial number of type key_serial_t that is unique for
the lifetime of that key. All serial numbers are positive non-zero 32-bit
integers.
Userspace programs can use a key's serial numbers as a way to gain access
to it, subject to permission checking.
* Each key is of a defined "type". Types must be registered inside the
kernel by a kernel service (such as a filesystem) before keys of that type
can be added or used. Userspace programs cannot define new types directly.
Key types are represented in the kernel by struct key_type. This defines a
number of operations that can be performed on a key of that type.
Should a type be removed from the system, all the keys of that type will
be invalidated.
* Each key has a description. This should be a printable string. The key
type provides an operation to perform a match between the description on a
key and a criterion string.
* Each key has an owner user ID, a group ID and a permissions mask. These
are used to control what a process may do to a key from userspace, and
whether a kernel service will be able to find the key.
* Each key can be set to expire at a specific time by the key type's
instantiation function. Keys can also be immortal.
* Each key can have a payload. This is a quantity of data that represent the
actual "key". In the case of a keyring, this is a list of keys to which
the keyring links; in the case of a user-defined key, it's an arbitrary
blob of data.
Having a payload is not required; and the payload can, in fact, just be a
value stored in the struct key itself.
When a key is instantiated, the key type's instantiation function is
called with a blob of data, and that then creates the key's payload in
some way.
Similarly, when userspace wants to read back the contents of the key, if
permitted, another key type operation will be called to convert the key's
attached payload back into a blob of data.
* Each key can be in one of a number of basic states:
* Uninstantiated. The key exists, but does not have any data attached.
Keys being requested from userspace will be in this state.
* Instantiated. This is the normal state. The key is fully formed, and
has data attached.
* Negative. This is a relatively short-lived state. The key acts as a
note saying that a previous call out to userspace failed, and acts as
a throttle on key lookups. A negative key can be updated to a normal
state.
* Expired. Keys can have lifetimes set. If their lifetime is exceeded,
they traverse to this state. An expired key can be updated back to a
normal state.
* Revoked. A key is put in this state by userspace action. It can't be
found or operated upon (apart from by unlinking it).
* Dead. The key's type was unregistered, and so the key is now useless.
Keys in the last three states are subject to garbage collection. See the
section on "Garbage collection".
Key Service Overview
====================
The key service provides a number of features besides keys:
* The key service defines three special key types:
(+) "keyring"
Keyrings are special keys that contain a list of other keys. Keyring
lists can be modified using various system calls. Keyrings should not
be given a payload when created.
(+) "user"
A key of this type has a description and a payload that are arbitrary
blobs of data. These can be created, updated and read by userspace,
and aren't intended for use by kernel services.
(+) "logon"
Like a "user" key, a "logon" key has a payload that is an arbitrary
blob of data. It is intended as a place to store secrets which are
accessible to the kernel but not to userspace programs.
The description can be arbitrary, but must be prefixed with a non-zero
length string that describes the key "subclass". The subclass is
separated from the rest of the description by a ':'. "logon" keys can
be created and updated from userspace, but the payload is only
readable from kernel space.
* Each process subscribes to three keyrings: a thread-specific keyring, a
process-specific keyring, and a session-specific keyring.
The thread-specific keyring is discarded from the child when any sort of
clone, fork, vfork or execve occurs. A new keyring is created only when
required.
The process-specific keyring is replaced with an empty one in the child on
clone, fork, vfork unless CLONE_THREAD is supplied, in which case it is
shared. execve also discards the process's process keyring and creates a
new one.
The session-specific keyring is persistent across clone, fork, vfork and
execve, even when the latter executes a set-UID or set-GID binary. A
process can, however, replace its current session keyring with a new one
by using PR_JOIN_SESSION_KEYRING. It is permitted to request an anonymous
new one, or to attempt to create or join one of a specific name.
The ownership of the thread keyring changes when the real UID and GID of
the thread changes.
* Each user ID resident in the system holds two special keyrings: a user
specific keyring and a default user session keyring. The default session
keyring is initialised with a link to the user-specific keyring.
When a process changes its real UID, if it used to have no session key, it
will be subscribed to the default session key for the new UID.
If a process attempts to access its session key when it doesn't have one,
it will be subscribed to the default for its current UID.
* Each user has two quotas against which the keys they own are tracked. One
limits the total number of keys and keyrings, the other limits the total
amount of description and payload space that can be consumed.
The user can view information on this and other statistics through procfs
files. The root user may also alter the quota limits through sysctl files
(see the section "New procfs files").
Process-specific and thread-specific keyrings are not counted towards a
user's quota.
If a system call that modifies a key or keyring in some way would put the
user over quota, the operation is refused and error EDQUOT is returned.
* There's a system call interface by which userspace programs can create and
manipulate keys and keyrings.
* There's a kernel interface by which services can register types and search
for keys.
* There's a way for the a search done from the kernel to call back to
userspace to request a key that can't be found in a process's keyrings.
* An optional filesystem is available through which the key database can be
viewed and manipulated.
Key Access Permissions
======================
Keys have an owner user ID, a group access ID, and a permissions mask. The mask
has up to eight bits each for possessor, user, group and other access. Only
six of each set of eight bits are defined. These permissions granted are:
* View
This permits a key or keyring's attributes to be viewed - including key
type and description.
* Read
This permits a key's payload to be viewed or a keyring's list of linked
keys.
* Write
This permits a key's payload to be instantiated or updated, or it allows a
link to be added to or removed from a keyring.
* Search
This permits keyrings to be searched and keys to be found. Searches can
only recurse into nested keyrings that have search permission set.
* Link
This permits a key or keyring to be linked to. To create a link from a
keyring to a key, a process must have Write permission on the keyring and
Link permission on the key.
* Set Attribute
This permits a key's UID, GID and permissions mask to be changed.
For changing the ownership, group ID or permissions mask, being the owner of
the key or having the sysadmin capability is sufficient.
SELinux Support
===============
The security class "key" has been added to SELinux so that mandatory access
controls can be applied to keys created within various contexts. This support
is preliminary, and is likely to change quite significantly in the near future.
Currently, all of the basic permissions explained above are provided in SELinux
as well; SELinux is simply invoked after all basic permission checks have been
performed.
The value of the file /proc/self/attr/keycreate influences the labeling of
newly-created keys. If the contents of that file correspond to an SELinux
security context, then the key will be assigned that context. Otherwise, the
key will be assigned the current context of the task that invoked the key
creation request. Tasks must be granted explicit permission to assign a
particular context to newly-created keys, using the "create" permission in the
key security class.
The default keyrings associated with users will be labeled with the default
context of the user if and only if the login programs have been instrumented to
properly initialize keycreate during the login process. Otherwise, they will
be labeled with the context of the login program itself.
Note, however, that the default keyrings associated with the root user are
labeled with the default kernel context, since they are created early in the
boot process, before root has a chance to log in.
The keyrings associated with new threads are each labeled with the context of
their associated thread, and both session and process keyrings are handled
similarly.
New ProcFS Files
================
Two files have been added to procfs by which an administrator can find out
about the status of the key service:
* /proc/keys
This lists the keys that are currently viewable by the task reading the
file, giving information about their type, description and permissions.
It is not possible to view the payload of the key this way, though some
information about it may be given.
The only keys included in the list are those that grant View permission to
the reading process whether or not it possesses them. Note that LSM
security checks are still performed, and may further filter out keys that
the current process is not authorised to view.
The contents of the file look like this::
SERIAL FLAGS USAGE EXPY PERM UID GID TYPE DESCRIPTION: SUMMARY
00000001 I----- 39 perm 1f3f0000 0 0 keyring _uid_ses.0: 1/4
00000002 I----- 2 perm 1f3f0000 0 0 keyring _uid.0: empty
00000007 I----- 1 perm 1f3f0000 0 0 keyring _pid.1: empty
0000018d I----- 1 perm 1f3f0000 0 0 keyring _pid.412: empty
000004d2 I--Q-- 1 perm 1f3f0000 32 -1 keyring _uid.32: 1/4
000004d3 I--Q-- 3 perm 1f3f0000 32 -1 keyring _uid_ses.32: empty
00000892 I--QU- 1 perm 1f000000 0 0 user metal:copper: 0
00000893 I--Q-N 1 35s 1f3f0000 0 0 user metal:silver: 0
00000894 I--Q-- 1 10h 003f0000 0 0 user metal:gold: 0
The flags are::
I Instantiated
R Revoked
D Dead
Q Contributes to user's quota
U Under construction by callback to userspace
N Negative key
* /proc/key-users
This file lists the tracking data for each user that has at least one key
on the system. Such data includes quota information and statistics::
[root@andromeda root]# cat /proc/key-users
0: 46 45/45 1/100 13/10000
29: 2 2/2 2/100 40/10000
32: 2 2/2 2/100 40/10000
38: 2 2/2 2/100 40/10000
The format of each line is::
<UID>: User ID to which this applies
<usage> Structure refcount
<inst>/<keys> Total number of keys and number instantiated
<keys>/<max> Key count quota
<bytes>/<max> Key size quota
Four new sysctl files have been added also for the purpose of controlling the
quota limits on keys:
* /proc/sys/kernel/keys/root_maxkeys
/proc/sys/kernel/keys/root_maxbytes
These files hold the maximum number of keys that root may have and the
maximum total number of bytes of data that root may have stored in those
keys.
* /proc/sys/kernel/keys/maxkeys
/proc/sys/kernel/keys/maxbytes
These files hold the maximum number of keys that each non-root user may
have and the maximum total number of bytes of data that each of those
users may have stored in their keys.
Root may alter these by writing each new limit as a decimal number string to
the appropriate file.
Userspace System Call Interface
===============================
Userspace can manipulate keys directly through three new syscalls: add_key,
request_key and keyctl. The latter provides a number of functions for
manipulating keys.
When referring to a key directly, userspace programs should use the key's
serial number (a positive 32-bit integer). However, there are some special
values available for referring to special keys and keyrings that relate to the
process making the call::
CONSTANT VALUE KEY REFERENCED
============================== ====== ===========================
KEY_SPEC_THREAD_KEYRING -1 thread-specific keyring
KEY_SPEC_PROCESS_KEYRING -2 process-specific keyring
KEY_SPEC_SESSION_KEYRING -3 session-specific keyring
KEY_SPEC_USER_KEYRING -4 UID-specific keyring
KEY_SPEC_USER_SESSION_KEYRING -5 UID-session keyring
KEY_SPEC_GROUP_KEYRING -6 GID-specific keyring
KEY_SPEC_REQKEY_AUTH_KEY -7 assumed request_key()
authorisation key
The main syscalls are:
* Create a new key of given type, description and payload and add it to the
nominated keyring::
key_serial_t add_key(const char *type, const char *desc,
const void *payload, size_t plen,
key_serial_t keyring);
If a key of the same type and description as that proposed already exists
in the keyring, this will try to update it with the given payload, or it
will return error EEXIST if that function is not supported by the key
type. The process must also have permission to write to the key to be able
to update it. The new key will have all user permissions granted and no
group or third party permissions.
Otherwise, this will attempt to create a new key of the specified type and
description, and to instantiate it with the supplied payload and attach it
to the keyring. In this case, an error will be generated if the process
does not have permission to write to the keyring.
If the key type supports it, if the description is NULL or an empty
string, the key type will try and generate a description from the content
of the payload.
The payload is optional, and the pointer can be NULL if not required by
the type. The payload is plen in size, and plen can be zero for an empty
payload.
A new keyring can be generated by setting type "keyring", the keyring name
as the description (or NULL) and setting the payload to NULL.
User defined keys can be created by specifying type "user". It is
recommended that a user defined key's description by prefixed with a type
ID and a colon, such as "krb5tgt:" for a Kerberos 5 ticket granting
ticket.
Any other type must have been registered with the kernel in advance by a
kernel service such as a filesystem.
The ID of the new or updated key is returned if successful.
* Search the process's keyrings for a key, potentially calling out to
userspace to create it::
key_serial_t request_key(const char *type, const char *description,
const char *callout_info,
key_serial_t dest_keyring);
This function searches all the process's keyrings in the order thread,
process, session for a matching key. This works very much like
KEYCTL_SEARCH, including the optional attachment of the discovered key to
a keyring.
If a key cannot be found, and if callout_info is not NULL, then
/sbin/request-key will be invoked in an attempt to obtain a key. The
callout_info string will be passed as an argument to the program.
To link a key into the destination keyring the key must grant link
permission on the key to the caller and the keyring must grant write
permission.
See also Documentation/security/keys/request-key.rst.
The keyctl syscall functions are:
* Map a special key ID to a real key ID for this process::
key_serial_t keyctl(KEYCTL_GET_KEYRING_ID, key_serial_t id,
int create);
The special key specified by "id" is looked up (with the key being created
if necessary) and the ID of the key or keyring thus found is returned if
it exists.
If the key does not yet exist, the key will be created if "create" is
non-zero; and the error ENOKEY will be returned if "create" is zero.
* Replace the session keyring this process subscribes to with a new one::
key_serial_t keyctl(KEYCTL_JOIN_SESSION_KEYRING, const char *name);
If name is NULL, an anonymous keyring is created attached to the process
as its session keyring, displacing the old session keyring.
If name is not NULL, if a keyring of that name exists, the process
attempts to attach it as the session keyring, returning an error if that
is not permitted; otherwise a new keyring of that name is created and
attached as the session keyring.
To attach to a named keyring, the keyring must have search permission for
the process's ownership.
The ID of the new session keyring is returned if successful.
* Update the specified key::
long keyctl(KEYCTL_UPDATE, key_serial_t key, const void *payload,
size_t plen);
This will try to update the specified key with the given payload, or it
will return error EOPNOTSUPP if that function is not supported by the key
type. The process must also have permission to write to the key to be able
to update it.
The payload is of length plen, and may be absent or empty as for
add_key().
* Revoke a key::
long keyctl(KEYCTL_REVOKE, key_serial_t key);
This makes a key unavailable for further operations. Further attempts to
use the key will be met with error EKEYREVOKED, and the key will no longer
be findable.
* Change the ownership of a key::
long keyctl(KEYCTL_CHOWN, key_serial_t key, uid_t uid, gid_t gid);
This function permits a key's owner and group ID to be changed. Either one
of uid or gid can be set to -1 to suppress that change.
Only the superuser can change a key's owner to something other than the
key's current owner. Similarly, only the superuser can change a key's
group ID to something other than the calling process's group ID or one of
its group list members.
* Change the permissions mask on a key::
long keyctl(KEYCTL_SETPERM, key_serial_t key, key_perm_t perm);
This function permits the owner of a key or the superuser to change the
permissions mask on a key.
Only bits the available bits are permitted; if any other bits are set,
error EINVAL will be returned.
* Describe a key::
long keyctl(KEYCTL_DESCRIBE, key_serial_t key, char *buffer,
size_t buflen);
This function returns a summary of the key's attributes (but not its
payload data) as a string in the buffer provided.
Unless there's an error, it always returns the amount of data it could
produce, even if that's too big for the buffer, but it won't copy more
than requested to userspace. If the buffer pointer is NULL then no copy
will take place.
A process must have view permission on the key for this function to be
successful.
If successful, a string is placed in the buffer in the following format::
<type>;<uid>;<gid>;<perm>;<description>
Where type and description are strings, uid and gid are decimal, and perm
is hexadecimal. A NUL character is included at the end of the string if
the buffer is sufficiently big.
This can be parsed with::
sscanf(buffer, "%[^;];%d;%d;%o;%s", type, &uid, &gid, &mode, desc);
* Clear out a keyring::
long keyctl(KEYCTL_CLEAR, key_serial_t keyring);
This function clears the list of keys attached to a keyring. The calling
process must have write permission on the keyring, and it must be a
keyring (or else error ENOTDIR will result).
This function can also be used to clear special kernel keyrings if they
are appropriately marked if the user has CAP_SYS_ADMIN capability. The
DNS resolver cache keyring is an example of this.
* Link a key into a keyring::
long keyctl(KEYCTL_LINK, key_serial_t keyring, key_serial_t key);
This function creates a link from the keyring to the key. The process must
have write permission on the keyring and must have link permission on the
key.
Should the keyring not be a keyring, error ENOTDIR will result; and if the
keyring is full, error ENFILE will result.
The link procedure checks the nesting of the keyrings, returning ELOOP if
it appears too deep or EDEADLK if the link would introduce a cycle.
Any links within the keyring to keys that match the new key in terms of
type and description will be discarded from the keyring as the new one is
added.
* Move a key from one keyring to another::
long keyctl(KEYCTL_MOVE,
key_serial_t id,
key_serial_t from_ring_id,
key_serial_t to_ring_id,
unsigned int flags);
Move the key specified by "id" from the keyring specified by
"from_ring_id" to the keyring specified by "to_ring_id". If the two
keyrings are the same, nothing is done.
"flags" can have KEYCTL_MOVE_EXCL set in it to cause the operation to fail
with EEXIST if a matching key exists in the destination keyring, otherwise
such a key will be replaced.
A process must have link permission on the key for this function to be
successful and write permission on both keyrings. Any errors that can
occur from KEYCTL_LINK also apply on the destination keyring here.
* Unlink a key or keyring from another keyring::
long keyctl(KEYCTL_UNLINK, key_serial_t keyring, key_serial_t key);
This function looks through the keyring for the first link to the
specified key, and removes it if found. Subsequent links to that key are
ignored. The process must have write permission on the keyring.
If the keyring is not a keyring, error ENOTDIR will result; and if the key
is not present, error ENOENT will be the result.
* Search a keyring tree for a key::
key_serial_t keyctl(KEYCTL_SEARCH, key_serial_t keyring,
const char *type, const char *description,
key_serial_t dest_keyring);
This searches the keyring tree headed by the specified keyring until a key
is found that matches the type and description criteria. Each keyring is
checked for keys before recursion into its children occurs.
The process must have search permission on the top level keyring, or else
error EACCES will result. Only keyrings that the process has search
permission on will be recursed into, and only keys and keyrings for which
a process has search permission can be matched. If the specified keyring
is not a keyring, ENOTDIR will result.
If the search succeeds, the function will attempt to link the found key
into the destination keyring if one is supplied (non-zero ID). All the
constraints applicable to KEYCTL_LINK apply in this case too.
Error ENOKEY, EKEYREVOKED or EKEYEXPIRED will be returned if the search
fails. On success, the resulting key ID will be returned.
* Read the payload data from a key::
long keyctl(KEYCTL_READ, key_serial_t keyring, char *buffer,
size_t buflen);
This function attempts to read the payload data from the specified key
into the buffer. The process must have read permission on the key to
succeed.
The returned data will be processed for presentation by the key type. For
instance, a keyring will return an array of key_serial_t entries
representing the IDs of all the keys to which it is subscribed. The user
defined key type will return its data as is. If a key type does not
implement this function, error EOPNOTSUPP will result.
If the specified buffer is too small, then the size of the buffer required
will be returned. Note that in this case, the contents of the buffer may
have been overwritten in some undefined way.
Otherwise, on success, the function will return the amount of data copied
into the buffer.
* Instantiate a partially constructed key::
long keyctl(KEYCTL_INSTANTIATE, key_serial_t key,
const void *payload, size_t plen,
key_serial_t keyring);
long keyctl(KEYCTL_INSTANTIATE_IOV, key_serial_t key,
const struct iovec *payload_iov, unsigned ioc,
key_serial_t keyring);
If the kernel calls back to userspace to complete the instantiation of a
key, userspace should use this call to supply data for the key before the
invoked process returns, or else the key will be marked negative
automatically.
The process must have write access on the key to be able to instantiate
it, and the key must be uninstantiated.
If a keyring is specified (non-zero), the key will also be linked into
that keyring, however all the constraints applying in KEYCTL_LINK apply in
this case too.
The payload and plen arguments describe the payload data as for add_key().
The payload_iov and ioc arguments describe the payload data in an iovec
array instead of a single buffer.
* Negatively instantiate a partially constructed key::
long keyctl(KEYCTL_NEGATE, key_serial_t key,
unsigned timeout, key_serial_t keyring);
long keyctl(KEYCTL_REJECT, key_serial_t key,
unsigned timeout, unsigned error, key_serial_t keyring);
If the kernel calls back to userspace to complete the instantiation of a
key, userspace should use this call mark the key as negative before the
invoked process returns if it is unable to fulfill the request.
The process must have write access on the key to be able to instantiate
it, and the key must be uninstantiated.
If a keyring is specified (non-zero), the key will also be linked into
that keyring, however all the constraints applying in KEYCTL_LINK apply in
this case too.
If the key is rejected, future searches for it will return the specified
error code until the rejected key expires. Negating the key is the same
as rejecting the key with ENOKEY as the error code.
* Set the default request-key destination keyring::
long keyctl(KEYCTL_SET_REQKEY_KEYRING, int reqkey_defl);
This sets the default keyring to which implicitly requested keys will be
attached for this thread. reqkey_defl should be one of these constants::
CONSTANT VALUE NEW DEFAULT KEYRING
====================================== ====== =======================
KEY_REQKEY_DEFL_NO_CHANGE -1 No change
KEY_REQKEY_DEFL_DEFAULT 0 Default[1]
KEY_REQKEY_DEFL_THREAD_KEYRING 1 Thread keyring
KEY_REQKEY_DEFL_PROCESS_KEYRING 2 Process keyring
KEY_REQKEY_DEFL_SESSION_KEYRING 3 Session keyring
KEY_REQKEY_DEFL_USER_KEYRING 4 User keyring
KEY_REQKEY_DEFL_USER_SESSION_KEYRING 5 User session keyring
KEY_REQKEY_DEFL_GROUP_KEYRING 6 Group keyring
The old default will be returned if successful and error EINVAL will be
returned if reqkey_defl is not one of the above values.
The default keyring can be overridden by the keyring indicated to the
request_key() system call.
Note that this setting is inherited across fork/exec.
[1] The default is: the thread keyring if there is one, otherwise
the process keyring if there is one, otherwise the session keyring if
there is one, otherwise the user default session keyring.
* Set the timeout on a key::
long keyctl(KEYCTL_SET_TIMEOUT, key_serial_t key, unsigned timeout);
This sets or clears the timeout on a key. The timeout can be 0 to clear
the timeout or a number of seconds to set the expiry time that far into
the future.
The process must have attribute modification access on a key to set its
timeout. Timeouts may not be set with this function on negative, revoked
or expired keys.
* Assume the authority granted to instantiate a key::
long keyctl(KEYCTL_ASSUME_AUTHORITY, key_serial_t key);
This assumes or divests the authority required to instantiate the
specified key. Authority can only be assumed if the thread has the
authorisation key associated with the specified key in its keyrings
somewhere.
Once authority is assumed, searches for keys will also search the
requester's keyrings using the requester's security label, UID, GID and
groups.
If the requested authority is unavailable, error EPERM will be returned,
likewise if the authority has been revoked because the target key is
already instantiated.
If the specified key is 0, then any assumed authority will be divested.
The assumed authoritative key is inherited across fork and exec.
* Get the LSM security context attached to a key::
long keyctl(KEYCTL_GET_SECURITY, key_serial_t key, char *buffer,
size_t buflen)
This function returns a string that represents the LSM security context
attached to a key in the buffer provided.
Unless there's an error, it always returns the amount of data it could
produce, even if that's too big for the buffer, but it won't copy more
than requested to userspace. If the buffer pointer is NULL then no copy
will take place.
A NUL character is included at the end of the string if the buffer is
sufficiently big. This is included in the returned count. If no LSM is
in force then an empty string will be returned.
A process must have view permission on the key for this function to be
successful.
* Install the calling process's session keyring on its parent::
long keyctl(KEYCTL_SESSION_TO_PARENT);
This functions attempts to install the calling process's session keyring
on to the calling process's parent, replacing the parent's current session
keyring.
The calling process must have the same ownership as its parent, the
keyring must have the same ownership as the calling process, the calling
process must have LINK permission on the keyring and the active LSM module
mustn't deny permission, otherwise error EPERM will be returned.
Error ENOMEM will be returned if there was insufficient memory to complete
the operation, otherwise 0 will be returned to indicate success.
The keyring will be replaced next time the parent process leaves the
kernel and resumes executing userspace.
* Invalidate a key::
long keyctl(KEYCTL_INVALIDATE, key_serial_t key);
This function marks a key as being invalidated and then wakes up the
garbage collector. The garbage collector immediately removes invalidated
keys from all keyrings and deletes the key when its reference count
reaches zero.
Keys that are marked invalidated become invisible to normal key operations
immediately, though they are still visible in /proc/keys until deleted
(they're marked with an 'i' flag).
A process must have search permission on the key for this function to be
successful.
* Compute a Diffie-Hellman shared secret or public key::
long keyctl(KEYCTL_DH_COMPUTE, struct keyctl_dh_params *params,
char *buffer, size_t buflen, struct keyctl_kdf_params *kdf);
The params struct contains serial numbers for three keys::
- The prime, p, known to both parties
- The local private key
- The base integer, which is either a shared generator or the
remote public key
The value computed is::
result = base ^ private (mod prime)
If the base is the shared generator, the result is the local
public key. If the base is the remote public key, the result is
the shared secret.
If the parameter kdf is NULL, the following applies:
- The buffer length must be at least the length of the prime, or zero.
- If the buffer length is nonzero, the length of the result is
returned when it is successfully calculated and copied in to the
buffer. When the buffer length is zero, the minimum required
buffer length is returned.
The kdf parameter allows the caller to apply a key derivation function
(KDF) on the Diffie-Hellman computation where only the result
of the KDF is returned to the caller. The KDF is characterized with
struct keyctl_kdf_params as follows:
- ``char *hashname`` specifies the NUL terminated string identifying
the hash used from the kernel crypto API and applied for the KDF
operation. The KDF implementation complies with SP800-56A as well
as with SP800-108 (the counter KDF).
- ``char *otherinfo`` specifies the OtherInfo data as documented in
SP800-56A section 5.8.1.2. The length of the buffer is given with
otherinfolen. The format of OtherInfo is defined by the caller.
The otherinfo pointer may be NULL if no OtherInfo shall be used.
This function will return error EOPNOTSUPP if the key type is not
supported, error ENOKEY if the key could not be found, or error
EACCES if the key is not readable by the caller. In addition, the
function will return EMSGSIZE when the parameter kdf is non-NULL
and either the buffer length or the OtherInfo length exceeds the
allowed length.
* Restrict keyring linkage::
long keyctl(KEYCTL_RESTRICT_KEYRING, key_serial_t keyring,
const char *type, const char *restriction);
An existing keyring can restrict linkage of additional keys by evaluating
the contents of the key according to a restriction scheme.
"keyring" is the key ID for an existing keyring to apply a restriction
to. It may be empty or may already have keys linked. Existing linked keys
will remain in the keyring even if the new restriction would reject them.
"type" is a registered key type.
"restriction" is a string describing how key linkage is to be restricted.
The format varies depending on the key type, and the string is passed to
the lookup_restriction() function for the requested type. It may specify
a method and relevant data for the restriction such as signature
verification or constraints on key payload. If the requested key type is
later unregistered, no keys may be added to the keyring after the key type
is removed.
To apply a keyring restriction the process must have Set Attribute
permission and the keyring must not be previously restricted.
One application of restricted keyrings is to verify X.509 certificate
chains or individual certificate signatures using the asymmetric key type.
See Documentation/crypto/asymmetric-keys.rst for specific restrictions
applicable to the asymmetric key type.
* Query an asymmetric key::
long keyctl(KEYCTL_PKEY_QUERY,
key_serial_t key_id, unsigned long reserved,
const char *params,
struct keyctl_pkey_query *info);
Get information about an asymmetric key. Specific algorithms and
encodings may be queried by using the ``params`` argument. This is a
string containing a space- or tab-separated string of key-value pairs.
Currently supported keys include ``enc`` and ``hash``. The information
is returned in the keyctl_pkey_query struct::
__u32 supported_ops;
__u32 key_size;
__u16 max_data_size;
__u16 max_sig_size;
__u16 max_enc_size;
__u16 max_dec_size;
__u32 __spare[10];
``supported_ops`` contains a bit mask of flags indicating which ops are
supported. This is constructed from a bitwise-OR of::
KEYCTL_SUPPORTS_{ENCRYPT,DECRYPT,SIGN,VERIFY}
``key_size`` indicated the size of the key in bits.
``max_*_size`` indicate the maximum sizes in bytes of a blob of data to be
signed, a signature blob, a blob to be encrypted and a blob to be
decrypted.
``__spare[]`` must be set to 0. This is intended for future use to hand
over one or more passphrases needed unlock a key.
If successful, 0 is returned. If the key is not an asymmetric key,
EOPNOTSUPP is returned.
* Encrypt, decrypt, sign or verify a blob using an asymmetric key::
long keyctl(KEYCTL_PKEY_ENCRYPT,
const struct keyctl_pkey_params *params,
const char *info,
const void *in,
void *out);
long keyctl(KEYCTL_PKEY_DECRYPT,
const struct keyctl_pkey_params *params,
const char *info,
const void *in,
void *out);
long keyctl(KEYCTL_PKEY_SIGN,
const struct keyctl_pkey_params *params,
const char *info,
const void *in,
void *out);
long keyctl(KEYCTL_PKEY_VERIFY,
const struct keyctl_pkey_params *params,
const char *info,
const void *in,
const void *in2);
Use an asymmetric key to perform a public-key cryptographic operation a
blob of data. For encryption and verification, the asymmetric key may
only need the public parts to be available, but for decryption and signing
the private parts are required also.
The parameter block pointed to by params contains a number of integer
values::
__s32 key_id;
__u32 in_len;
__u32 out_len;
__u32 in2_len;
``key_id`` is the ID of the asymmetric key to be used. ``in_len`` and
``in2_len`` indicate the amount of data in the in and in2 buffers and
``out_len`` indicates the size of the out buffer as appropriate for the
above operations.
For a given operation, the in and out buffers are used as follows::
Operation ID in,in_len out,out_len in2,in2_len
======================= =============== =============== ===============
KEYCTL_PKEY_ENCRYPT Raw data Encrypted data -
KEYCTL_PKEY_DECRYPT Encrypted data Raw data -
KEYCTL_PKEY_SIGN Raw data Signature -
KEYCTL_PKEY_VERIFY Raw data - Signature
``info`` is a string of key=value pairs that supply supplementary
information. These include:
``enc=<encoding>`` The encoding of the encrypted/signature blob. This
can be "pkcs1" for RSASSA-PKCS1-v1.5 or
RSAES-PKCS1-v1.5; "pss" for "RSASSA-PSS"; "oaep" for
"RSAES-OAEP". If omitted or is "raw", the raw output
of the encryption function is specified.
``hash=<algo>`` If the data buffer contains the output of a hash
function and the encoding includes some indication of
which hash function was used, the hash function can be
specified with this, eg. "hash=sha256".
The ``__spare[]`` space in the parameter block must be set to 0. This is
intended, amongst other things, to allow the passing of passphrases
required to unlock a key.
If successful, encrypt, decrypt and sign all return the amount of data
written into the output buffer. Verification returns 0 on success.
* Watch a key or keyring for changes::
long keyctl(KEYCTL_WATCH_KEY, key_serial_t key, int queue_fd,
const struct watch_notification_filter *filter);
This will set or remove a watch for changes on the specified key or
keyring.
"key" is the ID of the key to be watched.
"queue_fd" is a file descriptor referring to an open pipe which
manages the buffer into which notifications will be delivered.
"filter" is either NULL to remove a watch or a filter specification to
indicate what events are required from the key.
See Documentation/core-api/watch_queue.rst for more information.
Note that only one watch may be emplaced for any particular { key,
queue_fd } combination.
Notification records look like::
struct key_notification {
struct watch_notification watch;
__u32 key_id;
__u32 aux;
};
In this, watch::type will be "WATCH_TYPE_KEY_NOTIFY" and subtype will be
one of::
NOTIFY_KEY_INSTANTIATED
NOTIFY_KEY_UPDATED
NOTIFY_KEY_LINKED
NOTIFY_KEY_UNLINKED
NOTIFY_KEY_CLEARED
NOTIFY_KEY_REVOKED
NOTIFY_KEY_INVALIDATED
NOTIFY_KEY_SETATTR
Where these indicate a key being instantiated/rejected, updated, a link
being made in a keyring, a link being removed from a keyring, a keyring
being cleared, a key being revoked, a key being invalidated or a key
having one of its attributes changed (user, group, perm, timeout,
restriction).
If a watched key is deleted, a basic watch_notification will be issued
with "type" set to WATCH_TYPE_META and "subtype" set to
watch_meta_removal_notification. The watchpoint ID will be set in the
"info" field.
This needs to be configured by enabling:
"Provide key/keyring change notifications" (KEY_NOTIFICATIONS)
Kernel Services
===============
The kernel services for key management are fairly simple to deal with. They can
be broken down into two areas: keys and key types.
Dealing with keys is fairly straightforward. Firstly, the kernel service
registers its type, then it searches for a key of that type. It should retain
the key as long as it has need of it, and then it should release it. For a
filesystem or device file, a search would probably be performed during the open
call, and the key released upon close. How to deal with conflicting keys due to
two different users opening the same file is left to the filesystem author to
solve.
To access the key manager, the following header must be #included::
<linux/key.h>
Specific key types should have a header file under include/keys/ that should be
used to access that type. For keys of type "user", for example, that would be::
<keys/user-type.h>
Note that there are two different types of pointers to keys that may be
encountered:
* struct key *
This simply points to the key structure itself. Key structures will be at
least four-byte aligned.
* key_ref_t
This is equivalent to a ``struct key *``, but the least significant bit is set
if the caller "possesses" the key. By "possession" it is meant that the
calling processes has a searchable link to the key from one of its
keyrings. There are three functions for dealing with these::
key_ref_t make_key_ref(const struct key *key, bool possession);
struct key *key_ref_to_ptr(const key_ref_t key_ref);
bool is_key_possessed(const key_ref_t key_ref);
The first function constructs a key reference from a key pointer and
possession information (which must be true or false).
The second function retrieves the key pointer from a reference and the
third retrieves the possession flag.
When accessing a key's payload contents, certain precautions must be taken to
prevent access vs modification races. See the section "Notes on accessing
payload contents" for more information.
* To search for a key, call::
struct key *request_key(const struct key_type *type,
const char *description,
const char *callout_info);
This is used to request a key or keyring with a description that matches
the description specified according to the key type's match_preparse()
method. This permits approximate matching to occur. If callout_string is
not NULL, then /sbin/request-key will be invoked in an attempt to obtain
the key from userspace. In that case, callout_string will be passed as an
argument to the program.
Should the function fail error ENOKEY, EKEYEXPIRED or EKEYREVOKED will be
returned.
If successful, the key will have been attached to the default keyring for
implicitly obtained request-key keys, as set by KEYCTL_SET_REQKEY_KEYRING.
See also Documentation/security/keys/request-key.rst.
* To search for a key in a specific domain, call::
struct key *request_key_tag(const struct key_type *type,
const char *description,
struct key_tag *domain_tag,
const char *callout_info);
This is identical to request_key(), except that a domain tag may be
specifies that causes search algorithm to only match keys matching that
tag. The domain_tag may be NULL, specifying a global domain that is
separate from any nominated domain.
* To search for a key, passing auxiliary data to the upcaller, call::
struct key *request_key_with_auxdata(const struct key_type *type,
const char *description,
struct key_tag *domain_tag,
const void *callout_info,
size_t callout_len,
void *aux);
This is identical to request_key_tag(), except that the auxiliary data is
passed to the key_type->request_key() op if it exists, and the
callout_info is a blob of length callout_len, if given (the length may be
0).
* To search for a key under RCU conditions, call::
struct key *request_key_rcu(const struct key_type *type,
const char *description,
struct key_tag *domain_tag);
which is similar to request_key_tag() except that it does not check for
keys that are under construction and it will not call out to userspace to
construct a key if it can't find a match.
* When it is no longer required, the key should be released using::
void key_put(struct key *key);
Or::
void key_ref_put(key_ref_t key_ref);
These can be called from interrupt context. If CONFIG_KEYS is not set then
the argument will not be parsed.
* Extra references can be made to a key by calling one of the following
functions::
struct key *__key_get(struct key *key);
struct key *key_get(struct key *key);
Keys so references will need to be disposed of by calling key_put() when
they've been finished with. The key pointer passed in will be returned.
In the case of key_get(), if the pointer is NULL or CONFIG_KEYS is not set
then the key will not be dereferenced and no increment will take place.
* A key's serial number can be obtained by calling::
key_serial_t key_serial(struct key *key);
If key is NULL or if CONFIG_KEYS is not set then 0 will be returned (in the
latter case without parsing the argument).
* If a keyring was found in the search, this can be further searched by::
key_ref_t keyring_search(key_ref_t keyring_ref,
const struct key_type *type,
const char *description,
bool recurse)
This searches the specified keyring only (recurse == false) or keyring tree
(recurse == true) specified for a matching key. Error ENOKEY is returned
upon failure (use IS_ERR/PTR_ERR to determine). If successful, the returned
key will need to be released.
The possession attribute from the keyring reference is used to control
access through the permissions mask and is propagated to the returned key
reference pointer if successful.
* A keyring can be created by::
struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
const struct cred *cred,
key_perm_t perm,
struct key_restriction *restrict_link,
unsigned long flags,
struct key *dest);
This creates a keyring with the given attributes and returns it. If dest
is not NULL, the new keyring will be linked into the keyring to which it
points. No permission checks are made upon the destination keyring.
Error EDQUOT can be returned if the keyring would overload the quota (pass
KEY_ALLOC_NOT_IN_QUOTA in flags if the keyring shouldn't be accounted
towards the user's quota). Error ENOMEM can also be returned.
If restrict_link is not NULL, it should point to a structure that contains
the function that will be called each time an attempt is made to link a
key into the new keyring. The structure may also contain a key pointer
and an associated key type. The function is called to check whether a key
may be added into the keyring or not. The key type is used by the garbage
collector to clean up function or data pointers in this structure if the
given key type is unregistered. Callers of key_create_or_update() within
the kernel can pass KEY_ALLOC_BYPASS_RESTRICTION to suppress the check.
An example of using this is to manage rings of cryptographic keys that are
set up when the kernel boots where userspace is also permitted to add keys
- provided they can be verified by a key the kernel already has.
When called, the restriction function will be passed the keyring being
added to, the key type, the payload of the key being added, and data to be
used in the restriction check. Note that when a new key is being created,
this is called between payload preparsing and actual key creation. The
function should return 0 to allow the link or an error to reject it.
A convenience function, restrict_link_reject, exists to always return
-EPERM to in this case.
* To check the validity of a key, this function can be called::
int validate_key(struct key *key);
This checks that the key in question hasn't expired or and hasn't been
revoked. Should the key be invalid, error EKEYEXPIRED or EKEYREVOKED will
be returned. If the key is NULL or if CONFIG_KEYS is not set then 0 will be
returned (in the latter case without parsing the argument).
* To register a key type, the following function should be called::
int register_key_type(struct key_type *type);
This will return error EEXIST if a type of the same name is already
present.
* To unregister a key type, call::
void unregister_key_type(struct key_type *type);
Under some circumstances, it may be desirable to deal with a bundle of keys.
The facility provides access to the keyring type for managing such a bundle::
struct key_type key_type_keyring;
This can be used with a function such as request_key() to find a specific
keyring in a process's keyrings. A keyring thus found can then be searched
with keyring_search(). Note that it is not possible to use request_key() to
search a specific keyring, so using keyrings in this way is of limited utility.
Notes On Accessing Payload Contents
===================================
The simplest payload is just data stored in key->payload directly. In this
case, there's no need to indulge in RCU or locking when accessing the payload.
More complex payload contents must be allocated and pointers to them set in the
key->payload.data[] array. One of the following ways must be selected to
access the data:
1) Unmodifiable key type.
If the key type does not have a modify method, then the key's payload can
be accessed without any form of locking, provided that it's known to be
instantiated (uninstantiated keys cannot be "found").
2) The key's semaphore.
The semaphore could be used to govern access to the payload and to control
the payload pointer. It must be write-locked for modifications and would
have to be read-locked for general access. The disadvantage of doing this
is that the accessor may be required to sleep.
3) RCU.
RCU must be used when the semaphore isn't already held; if the semaphore
is held then the contents can't change under you unexpectedly as the
semaphore must still be used to serialise modifications to the key. The
key management code takes care of this for the key type.
However, this means using::
rcu_read_lock() ... rcu_dereference() ... rcu_read_unlock()
to read the pointer, and::
rcu_dereference() ... rcu_assign_pointer() ... call_rcu()
to set the pointer and dispose of the old contents after a grace period.
Note that only the key type should ever modify a key's payload.
Furthermore, an RCU controlled payload must hold a struct rcu_head for the
use of call_rcu() and, if the payload is of variable size, the length of
the payload. key->datalen cannot be relied upon to be consistent with the
payload just dereferenced if the key's semaphore is not held.
Note that key->payload.data[0] has a shadow that is marked for __rcu
usage. This is called key->payload.rcu_data0. The following accessors
wrap the RCU calls to this element:
a) Set or change the first payload pointer::
rcu_assign_keypointer(struct key *key, void *data);
b) Read the first payload pointer with the key semaphore held::
[const] void *dereference_key_locked([const] struct key *key);
Note that the return value will inherit its constness from the key
parameter. Static analysis will give an error if it things the lock
isn't held.
c) Read the first payload pointer with the RCU read lock held::
const void *dereference_key_rcu(const struct key *key);
Defining a Key Type
===================
A kernel service may want to define its own key type. For instance, an AFS
filesystem might want to define a Kerberos 5 ticket key type. To do this, it
author fills in a key_type struct and registers it with the system.
Source files that implement key types should include the following header file::
<linux/key-type.h>
The structure has a number of fields, some of which are mandatory:
* ``const char *name``
The name of the key type. This is used to translate a key type name
supplied by userspace into a pointer to the structure.
* ``size_t def_datalen``
This is optional - it supplies the default payload data length as
contributed to the quota. If the key type's payload is always or almost
always the same size, then this is a more efficient way to do things.
The data length (and quota) on a particular key can always be changed
during instantiation or update by calling::
int key_payload_reserve(struct key *key, size_t datalen);
With the revised data length. Error EDQUOT will be returned if this is not
viable.
* ``int (*vet_description)(const char *description);``
This optional method is called to vet a key description. If the key type
doesn't approve of the key description, it may return an error, otherwise
it should return 0.
* ``int (*preparse)(struct key_preparsed_payload *prep);``
This optional method permits the key type to attempt to parse payload
before a key is created (add key) or the key semaphore is taken (update or
instantiate key). The structure pointed to by prep looks like::
struct key_preparsed_payload {
char *description;
union key_payload payload;
const void *data;
size_t datalen;
size_t quotalen;
time_t expiry;
};
Before calling the method, the caller will fill in data and datalen with
the payload blob parameters; quotalen will be filled in with the default
quota size from the key type; expiry will be set to TIME_T_MAX and the
rest will be cleared.
If a description can be proposed from the payload contents, that should be
attached as a string to the description field. This will be used for the
key description if the caller of add_key() passes NULL or "".
The method can attach anything it likes to payload. This is merely passed
along to the instantiate() or update() operations. If set, the expiry
time will be applied to the key if it is instantiated from this data.
The method should return 0 if successful or a negative error code
otherwise.
* ``void (*free_preparse)(struct key_preparsed_payload *prep);``
This method is only required if the preparse() method is provided,
otherwise it is unused. It cleans up anything attached to the description
and payload fields of the key_preparsed_payload struct as filled in by the
preparse() method. It will always be called after preparse() returns
successfully, even if instantiate() or update() succeed.
* ``int (*instantiate)(struct key *key, struct key_preparsed_payload *prep);``
This method is called to attach a payload to a key during construction.
The payload attached need not bear any relation to the data passed to this
function.
The prep->data and prep->datalen fields will define the original payload
blob. If preparse() was supplied then other fields may be filled in also.
If the amount of data attached to the key differs from the size in
keytype->def_datalen, then key_payload_reserve() should be called.
This method does not have to lock the key in order to attach a payload.
The fact that KEY_FLAG_INSTANTIATED is not set in key->flags prevents
anything else from gaining access to the key.
It is safe to sleep in this method.
generic_key_instantiate() is provided to simply copy the data from
prep->payload.data[] to key->payload.data[], with RCU-safe assignment on
the first element. It will then clear prep->payload.data[] so that the
free_preparse method doesn't release the data.
* ``int (*update)(struct key *key, const void *data, size_t datalen);``
If this type of key can be updated, then this method should be provided.
It is called to update a key's payload from the blob of data provided.
The prep->data and prep->datalen fields will define the original payload
blob. If preparse() was supplied then other fields may be filled in also.
key_payload_reserve() should be called if the data length might change
before any changes are actually made. Note that if this succeeds, the type
is committed to changing the key because it's already been altered, so all
memory allocation must be done first.
The key will have its semaphore write-locked before this method is called,
but this only deters other writers; any changes to the key's payload must
be made under RCU conditions, and call_rcu() must be used to dispose of
the old payload.
key_payload_reserve() should be called before the changes are made, but
after all allocations and other potentially failing function calls are
made.
It is safe to sleep in this method.
* ``int (*match_preparse)(struct key_match_data *match_data);``
This method is optional. It is called when a key search is about to be
performed. It is given the following structure::
struct key_match_data {
bool (*cmp)(const struct key *key,
const struct key_match_data *match_data);
const void *raw_data;
void *preparsed;
unsigned lookup_type;
};
On entry, raw_data will be pointing to the criteria to be used in matching
a key by the caller and should not be modified. ``(*cmp)()`` will be pointing
to the default matcher function (which does an exact description match
against raw_data) and lookup_type will be set to indicate a direct lookup.
The following lookup_type values are available:
* KEYRING_SEARCH_LOOKUP_DIRECT - A direct lookup hashes the type and
description to narrow down the search to a small number of keys.
* KEYRING_SEARCH_LOOKUP_ITERATE - An iterative lookup walks all the
keys in the keyring until one is matched. This must be used for any
search that's not doing a simple direct match on the key description.
The method may set cmp to point to a function of its choice that does some
other form of match, may set lookup_type to KEYRING_SEARCH_LOOKUP_ITERATE
and may attach something to the preparsed pointer for use by ``(*cmp)()``.
``(*cmp)()`` should return true if a key matches and false otherwise.
If preparsed is set, it may be necessary to use the match_free() method to
clean it up.
The method should return 0 if successful or a negative error code
otherwise.
It is permitted to sleep in this method, but ``(*cmp)()`` may not sleep as
locks will be held over it.
If match_preparse() is not provided, keys of this type will be matched
exactly by their description.
* ``void (*match_free)(struct key_match_data *match_data);``
This method is optional. If given, it called to clean up
match_data->preparsed after a successful call to match_preparse().
* ``void (*revoke)(struct key *key);``
This method is optional. It is called to discard part of the payload
data upon a key being revoked. The caller will have the key semaphore
write-locked.
It is safe to sleep in this method, though care should be taken to avoid
a deadlock against the key semaphore.
* ``void (*destroy)(struct key *key);``
This method is optional. It is called to discard the payload data on a key
when it is being destroyed.
This method does not need to lock the key to access the payload; it can
consider the key as being inaccessible at this time. Note that the key's
type may have been changed before this function is called.
It is not safe to sleep in this method; the caller may hold spinlocks.
* ``void (*describe)(const struct key *key, struct seq_file *p);``
This method is optional. It is called during /proc/keys reading to
summarise a key's description and payload in text form.
This method will be called with the RCU read lock held. rcu_dereference()
should be used to read the payload pointer if the payload is to be
accessed. key->datalen cannot be trusted to stay consistent with the
contents of the payload.
The description will not change, though the key's state may.
It is not safe to sleep in this method; the RCU read lock is held by the
caller.
* ``long (*read)(const struct key *key, char __user *buffer, size_t buflen);``
This method is optional. It is called by KEYCTL_READ to translate the
key's payload into something a blob of data for userspace to deal with.
Ideally, the blob should be in the same format as that passed in to the
instantiate and update methods.
If successful, the blob size that could be produced should be returned
rather than the size copied.
This method will be called with the key's semaphore read-locked. This will
prevent the key's payload changing. It is not necessary to use RCU locking
when accessing the key's payload. It is safe to sleep in this method, such
as might happen when the userspace buffer is accessed.
* ``int (*request_key)(struct key_construction *cons, const char *op, void *aux);``
This method is optional. If provided, request_key() and friends will
invoke this function rather than upcalling to /sbin/request-key to operate
upon a key of this type.
The aux parameter is as passed to request_key_async_with_auxdata() and
similar or is NULL otherwise. Also passed are the construction record for
the key to be operated upon and the operation type (currently only
"create").
This method is permitted to return before the upcall is complete, but the
following function must be called under all circumstances to complete the
instantiation process, whether or not it succeeds, whether or not there's
an error::
void complete_request_key(struct key_construction *cons, int error);
The error parameter should be 0 on success, -ve on error. The
construction record is destroyed by this action and the authorisation key
will be revoked. If an error is indicated, the key under construction
will be negatively instantiated if it wasn't already instantiated.
If this method returns an error, that error will be returned to the
caller of request_key*(). complete_request_key() must be called prior to
returning.
The key under construction and the authorisation key can be found in the
key_construction struct pointed to by cons:
* ``struct key *key;``
The key under construction.
* ``struct key *authkey;``
The authorisation key.
* ``struct key_restriction *(*lookup_restriction)(const char *params);``
This optional method is used to enable userspace configuration of keyring
restrictions. The restriction parameter string (not including the key type
name) is passed in, and this method returns a pointer to a key_restriction
structure containing the relevant functions and data to evaluate each
attempted key link operation. If there is no match, -EINVAL is returned.
* ``asym_eds_op`` and ``asym_verify_signature``::
int (*asym_eds_op)(struct kernel_pkey_params *params,
const void *in, void *out);
int (*asym_verify_signature)(struct kernel_pkey_params *params,
const void *in, const void *in2);
These methods are optional. If provided the first allows a key to be
used to encrypt, decrypt or sign a blob of data, and the second allows a
key to verify a signature.
In all cases, the following information is provided in the params block::
struct kernel_pkey_params {
struct key *key;
const char *encoding;
const char *hash_algo;
char *info;
__u32 in_len;
union {
__u32 out_len;
__u32 in2_len;
};
enum kernel_pkey_operation op : 8;
};
This includes the key to be used; a string indicating the encoding to use
(for instance, "pkcs1" may be used with an RSA key to indicate
RSASSA-PKCS1-v1.5 or RSAES-PKCS1-v1.5 encoding or "raw" if no encoding);
the name of the hash algorithm used to generate the data for a signature
(if appropriate); the sizes of the input and output (or second input)
buffers; and the ID of the operation to be performed.
For a given operation ID, the input and output buffers are used as
follows::
Operation ID in,in_len out,out_len in2,in2_len
======================= =============== =============== ===============
kernel_pkey_encrypt Raw data Encrypted data -
kernel_pkey_decrypt Encrypted data Raw data -
kernel_pkey_sign Raw data Signature -
kernel_pkey_verify Raw data - Signature
asym_eds_op() deals with encryption, decryption and signature creation as
specified by params->op. Note that params->op is also set for
asym_verify_signature().
Encrypting and signature creation both take raw data in the input buffer
and return the encrypted result in the output buffer. Padding may have
been added if an encoding was set. In the case of signature creation,
depending on the encoding, the padding created may need to indicate the
digest algorithm - the name of which should be supplied in hash_algo.
Decryption takes encrypted data in the input buffer and returns the raw
data in the output buffer. Padding will get checked and stripped off if
an encoding was set.
Verification takes raw data in the input buffer and the signature in the
second input buffer and checks that the one matches the other. Padding
will be validated. Depending on the encoding, the digest algorithm used
to generate the raw data may need to be indicated in hash_algo.
If successful, asym_eds_op() should return the number of bytes written
into the output buffer. asym_verify_signature() should return 0.
A variety of errors may be returned, including EOPNOTSUPP if the operation
is not supported; EKEYREJECTED if verification fails; ENOPKG if the
required crypto isn't available.
* ``asym_query``::
int (*asym_query)(const struct kernel_pkey_params *params,
struct kernel_pkey_query *info);
This method is optional. If provided it allows information about the
public or asymmetric key held in the key to be determined.
The parameter block is as for asym_eds_op() and co. but in_len and out_len
are unused. The encoding and hash_algo fields should be used to reduce
the returned buffer/data sizes as appropriate.
If successful, the following information is filled in::
struct kernel_pkey_query {
__u32 supported_ops;
__u32 key_size;
__u16 max_data_size;
__u16 max_sig_size;
__u16 max_enc_size;
__u16 max_dec_size;
};
The supported_ops field will contain a bitmask indicating what operations
are supported by the key, including encryption of a blob, decryption of a
blob, signing a blob and verifying the signature on a blob. The following
constants are defined for this::
KEYCTL_SUPPORTS_{ENCRYPT,DECRYPT,SIGN,VERIFY}
The key_size field is the size of the key in bits. max_data_size and
max_sig_size are the maximum raw data and signature sizes for creation and
verification of a signature; max_enc_size and max_dec_size are the maximum
raw data and signature sizes for encryption and decryption. The
max_*_size fields are measured in bytes.
If successful, 0 will be returned. If the key doesn't support this,
EOPNOTSUPP will be returned.
Request-Key Callback Service
============================
To create a new key, the kernel will attempt to execute the following command
line::
/sbin/request-key create <key> <uid> <gid> \
<threadring> <processring> <sessionring> <callout_info>
<key> is the key being constructed, and the three keyrings are the process
keyrings from the process that caused the search to be issued. These are
included for two reasons:
1 There may be an authentication token in one of the keyrings that is
required to obtain the key, eg: a Kerberos Ticket-Granting Ticket.
2 The new key should probably be cached in one of these rings.
This program should set it UID and GID to those specified before attempting to
access any more keys. It may then look around for a user specific process to
hand the request off to (perhaps a path held in placed in another key by, for
example, the KDE desktop manager).
The program (or whatever it calls) should finish construction of the key by
calling KEYCTL_INSTANTIATE or KEYCTL_INSTANTIATE_IOV, which also permits it to
cache the key in one of the keyrings (probably the session ring) before
returning. Alternatively, the key can be marked as negative with KEYCTL_NEGATE
or KEYCTL_REJECT; this also permits the key to be cached in one of the
keyrings.
If it returns with the key remaining in the unconstructed state, the key will
be marked as being negative, it will be added to the session keyring, and an
error will be returned to the key requestor.
Supplementary information may be provided from whoever or whatever invoked this
service. This will be passed as the <callout_info> parameter. If no such
information was made available, then "-" will be passed as this parameter
instead.
Similarly, the kernel may attempt to update an expired or a soon to expire key
by executing::
/sbin/request-key update <key> <uid> <gid> \
<threadring> <processring> <sessionring>
In this case, the program isn't required to actually attach the key to a ring;
the rings are provided for reference.
Garbage Collection
==================
Dead keys (for which the type has been removed) will be automatically unlinked
from those keyrings that point to them and deleted as soon as possible by a
background garbage collector.
Similarly, revoked and expired keys will be garbage collected, but only after a
certain amount of time has passed. This time is set as a number of seconds in::
/proc/sys/kernel/keys/gc_delay
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
키 보존 서비스와 CONFIG_KEYS
1-21커널 키 보존 서비스는 암호화 키, 인증 토큰, 도메인 간 사용자 매핑 등을 커널에 캐시해 파일 시스템과 다른 커널 서비스가 사용하게 한다. 다른 키로 향하는 링크를 담는 특수 키인 keyring을 지원하며, 각 프로세스는 커널 서비스가 관련 키를 검색할 수 있는 세 표준 keyring 구독을 가진다.
기능은 `Security options`의 `Enable access key retention support`, 즉 `CONFIG_KEYS`로 활성화한다. 이 문서는 키 모델, 사용자 공간 API, 커널 서비스와 key type, request-key callback, garbage collection까지 다룬다.
============================
Kernel Key Retention Service
============================
This service allows cryptographic keys, authentication tokens, cross-domain
user mappings, and similar to be cached in the kernel for the use of
filesystems and other kernel services.
Keyrings are permitted; these are a special type of key that can hold links to
other keys. Processes each have three standard keyring subscriptions that a
kernel service can search for relevant keys.
The key service can be configured on by enabling:
"Security options"/"Enable access key retention support" (CONFIG_KEYS)
This document has the following sections:
.. contents:: :local:
struct key의 속성과 상태
22-108이 문맥에서 key는 암호 데이터, 인증 토큰, keyring 등의 단위이며 커널에서는 `struct key`로 표현된다. 각 key에는 serial number, type, 검색용 description, 접근 제어 정보, 만료 시각, payload, 상태가 있다. `key_serial_t` serial은 key 수명 동안 고유한 양의 0이 아닌 32비트 정수이며 사용자 공간은 권한 검사 아래 이 번호로 key를 참조한다.
key type은 해당 종류의 key가 추가·사용되기 전에 파일 시스템 같은 커널 서비스가 `struct key_type`으로 등록해야 하며 사용자 공간은 새 type을 직접 정의할 수 없다. type이 제거되면 그 type의 모든 key가 invalidated된다. printable description은 type별 match 연산으로 검색 기준 문자열과 비교한다. owner UID, group ID, permission mask는 사용자 공간 연산과 커널 검색 가능 여부를 통제한다.
type의 instantiate 함수는 key를 특정 시각에 만료되게 하거나 immortal로 둘 수 있고 입력 blob에서 payload를 만든다. payload는 keyring의 링크 목록이나 user key의 임의 blob일 수 있으며 없어도 되고 `struct key` 안의 값일 수도 있다. read 연산은 내부 payload를 사용자 공간 blob으로 변환한다.
상태는 payload가 없는 `Uninstantiated`, 정상 완성 상태인 `Instantiated`, 사용자 공간 요청 실패를 잠시 기록해 검색을 throttle하는 `Negative`, lifetime이 지난 `Expired`, 사용자 동작으로 더 이상 검색·연산할 수 없는 `Revoked`, type unregister로 쓸 수 없어진 `Dead`가 있다. Negative와 Expired는 update로 정상 상태가 될 수 있고, Expired·Revoked·Dead는 garbage collection 대상이다.
키 생성·요청·만료·폐기의 주요 상태다.
Key Overview
============
In this context, keys represent units of cryptographic data, authentication
tokens, keyrings, etc.. These are represented in the kernel by struct key.
Each key has a number of attributes:
- A serial number.
- A type.
- A description (for matching a key in a search).
- Access control information.
- An expiry time.
- A payload.
- State.
* Each key is issued a serial number of type key_serial_t that is unique for
the lifetime of that key. All serial numbers are positive non-zero 32-bit
integers.
Userspace programs can use a key's serial numbers as a way to gain access
to it, subject to permission checking.
* Each key is of a defined "type". Types must be registered inside the
kernel by a kernel service (such as a filesystem) before keys of that type
can be added or used. Userspace programs cannot define new types directly.
Key types are represented in the kernel by struct key_type. This defines a
number of operations that can be performed on a key of that type.
Should a type be removed from the system, all the keys of that type will
be invalidated.
* Each key has a description. This should be a printable string. The key
type provides an operation to perform a match between the description on a
key and a criterion string.
* Each key has an owner user ID, a group ID and a permissions mask. These
are used to control what a process may do to a key from userspace, and
whether a kernel service will be able to find the key.
* Each key can be set to expire at a specific time by the key type's
instantiation function. Keys can also be immortal.
* Each key can have a payload. This is a quantity of data that represent the
actual "key". In the case of a keyring, this is a list of keys to which
the keyring links; in the case of a user-defined key, it's an arbitrary
blob of data.
Having a payload is not required; and the payload can, in fact, just be a
value stored in the struct key itself.
When a key is instantiated, the key type's instantiation function is
called with a blob of data, and that then creates the key's payload in
some way.
Similarly, when userspace wants to read back the contents of the key, if
permitted, another key type operation will be called to convert the key's
attached payload back into a blob of data.
* Each key can be in one of a number of basic states:
* Uninstantiated. The key exists, but does not have any data attached.
Keys being requested from userspace will be in this state.
* Instantiated. This is the normal state. The key is fully formed, and
has data attached.
* Negative. This is a relatively short-lived state. The key acts as a
note saying that a previous call out to userspace failed, and acts as
a throttle on key lookups. A negative key can be updated to a normal
state.
* Expired. Keys can have lifetimes set. If their lifetime is exceeded,
they traverse to this state. An expired key can be updated back to a
normal state.
* Revoked. A key is put in this state by userspace action. It can't be
found or operated upon (apart from by unlinking it).
* Dead. The key's type was unregistered, and so the key is now useless.
Keys in the last three states are subject to garbage collection. See the
section on "Garbage collection".
표준 key type, 프로세스 keyring과 quota
109-197서비스는 `keyring`, `user`, `logon` 세 특수 type을 정의한다. `keyring`은 다른 key 링크 목록이며 system call로 수정하고 생성 payload를 주지 않는다. `user`는 임의 description과 payload blob을 사용자 공간이 생성·update·read하며 커널 서비스용은 아니다. `logon`은 kernel이 읽고 사용자 공간은 읽지 못하는 secret 저장소다. description은 길이 0이 아닌 subclass와 `:` 접두사가 필요하며 사용자 공간은 생성·update할 수 있다.
각 프로세스는 thread·process·session keyring을 구독한다. thread keyring은 clone·fork·vfork·execve 때 자식에서 버리고 필요할 때 새로 만든다. process keyring은 `CLONE_THREAD`이면 공유하지만 그 밖의 clone·fork·vfork에서는 자식이 빈 keyring으로 교체하고 execve도 새로 만든다. session keyring은 set-UID/set-GID 실행을 포함해 이 연산들을 넘어 유지되며 `PR_JOIN_SESSION_KEYRING`으로 익명 또는 이름 있는 keyring을 만들거나 join할 수 있다. 실제 UID/GID가 바뀌면 thread keyring 소유권도 바뀐다.
시스템에 존재하는 각 UID는 user-specific keyring과 default user session keyring을 가지며 후자는 전자로의 링크로 초기화된다. session key가 없던 프로세스가 실제 UID를 바꾸거나 session key에 접근하면 현재 UID의 기본 session keyring을 구독한다.
사용자별 quota는 소유한 key·keyring 수와 description·payload 총 바이트를 제한한다. process·thread keyring은 quota에 세지 않는다. 수정 연산이 한도를 넘으면 `EDQUOT`다. 상태와 통계는 procfs에서 보고 root는 sysctl로 한도를 바꾼다. 사용자 공간 system call, 커널 type 등록·검색, 찾지 못한 key의 사용자 공간 callback, 선택적 key database 파일 시스템도 제공된다.
내장 type의 payload 공개 범위가 다르다.
fork 계열과 execve에서 구독이 어떻게 변하는지 요약한다.
Key Service Overview
====================
The key service provides a number of features besides keys:
* The key service defines three special key types:
(+) "keyring"
Keyrings are special keys that contain a list of other keys. Keyring
lists can be modified using various system calls. Keyrings should not
be given a payload when created.
(+) "user"
A key of this type has a description and a payload that are arbitrary
blobs of data. These can be created, updated and read by userspace,
and aren't intended for use by kernel services.
(+) "logon"
Like a "user" key, a "logon" key has a payload that is an arbitrary
blob of data. It is intended as a place to store secrets which are
accessible to the kernel but not to userspace programs.
The description can be arbitrary, but must be prefixed with a non-zero
length string that describes the key "subclass". The subclass is
separated from the rest of the description by a ':'. "logon" keys can
be created and updated from userspace, but the payload is only
readable from kernel space.
* Each process subscribes to three keyrings: a thread-specific keyring, a
process-specific keyring, and a session-specific keyring.
The thread-specific keyring is discarded from the child when any sort of
clone, fork, vfork or execve occurs. A new keyring is created only when
required.
The process-specific keyring is replaced with an empty one in the child on
clone, fork, vfork unless CLONE_THREAD is supplied, in which case it is
shared. execve also discards the process's process keyring and creates a
new one.
The session-specific keyring is persistent across clone, fork, vfork and
execve, even when the latter executes a set-UID or set-GID binary. A
process can, however, replace its current session keyring with a new one
by using PR_JOIN_SESSION_KEYRING. It is permitted to request an anonymous
new one, or to attempt to create or join one of a specific name.
The ownership of the thread keyring changes when the real UID and GID of
the thread changes.
* Each user ID resident in the system holds two special keyrings: a user
specific keyring and a default user session keyring. The default session
keyring is initialised with a link to the user-specific keyring.
When a process changes its real UID, if it used to have no session key, it
will be subscribed to the default session key for the new UID.
If a process attempts to access its session key when it doesn't have one,
it will be subscribed to the default for its current UID.
* Each user has two quotas against which the keys they own are tracked. One
limits the total number of keys and keyrings, the other limits the total
amount of description and payload space that can be consumed.
The user can view information on this and other statistics through procfs
files. The root user may also alter the quota limits through sysctl files
(see the section "New procfs files").
Process-specific and thread-specific keyrings are not counted towards a
user's quota.
If a system call that modifies a key or keyring in some way would put the
user over quota, the operation is refused and error EDQUOT is returned.
* There's a system call interface by which userspace programs can create and
manipulate keys and keyrings.
* There's a kernel interface by which services can register types and search
for keys.
* There's a way for the a search done from the kernel to call back to
userspace to request a key that can't be found in a process's keyrings.
* An optional filesystem is available through which the key database can be
viewed and manipulated.
Possessor·User·Group·Other 권한
198-238key에는 owner UID, group access ID, permission mask가 있다. mask는 possessor·user·group·other마다 최대 8비트를 두지만 각 집합에서 6비트만 정의된다. `View`는 type·description 같은 속성, `Read`는 payload 또는 keyring 링크 목록, `Write`는 payload instantiate/update나 keyring 링크 추가·제거를 허용한다.
`Search`는 keyring 검색과 key 발견을 허용하며 search 권한이 있는 중첩 keyring으로만 재귀한다. `Link`는 해당 key로 링크를 만들 권한이다. keyring에서 key로 링크하려면 keyring의 Write와 key의 Link가 모두 필요하다. `Set Attribute`는 UID·GID·permission mask 변경을 허용한다. 소유권·그룹·mask 변경은 key owner이거나 sysadmin capability가 있으면 충분하다.
권한은 possessor·user·group·other 각각에 적용된다.
Key Access Permissions
======================
Keys have an owner user ID, a group access ID, and a permissions mask. The mask
has up to eight bits each for possessor, user, group and other access. Only
six of each set of eight bits are defined. These permissions granted are:
* View
This permits a key or keyring's attributes to be viewed - including key
type and description.
* Read
This permits a key's payload to be viewed or a keyring's list of linked
keys.
* Write
This permits a key's payload to be instantiated or updated, or it allows a
link to be added to or removed from a keyring.
* Search
This permits keyrings to be searched and keys to be found. Searches can
only recurse into nested keyrings that have search permission set.
* Link
This permits a key or keyring to be linked to. To create a link from a
keyring to a key, a process must have Write permission on the keyring and
Link permission on the key.
* Set Attribute
This permits a key's UID, GID and permissions mask to be changed.
For changing the ownership, group ID or permissions mask, being the owner of
the key or having the sysadmin capability is sufficient.
SELinux key class와 keycreate
239-270SELinux에는 여러 문맥에서 생성된 key에 MAC을 적용하도록 `key` security class가 추가됐다. 문서 시점의 지원은 초기 단계다. 앞의 기본 권한 검사를 모두 수행한 뒤 SELinux 검사를 호출하며 기본 권한 6종도 SELinux에 제공된다.
`/proc/self/attr/keycreate` 값이 SELinux security context이면 새 key에 그 문맥을 붙이고, 아니면 생성 요청 태스크의 현재 문맥을 쓴다. 새 key에 특정 문맥을 지정하려면 key class의 `create` 권한을 명시적으로 받아야 한다. 로그인 프로그램이 login 중 keycreate를 올바르게 초기화한 경우에만 사용자 기본 keyring이 사용자 기본 문맥을 가지며, 아니면 로그인 프로그램 문맥을 가진다.
root의 기본 keyring은 root 로그인 전에 부팅 초기에 생성되므로 default kernel context를 쓴다. 새 thread의 keyring은 해당 thread 문맥, session·process keyring도 각각 연결된 문맥으로 레이블된다.
SELinux Support
===============
The security class "key" has been added to SELinux so that mandatory access
controls can be applied to keys created within various contexts. This support
is preliminary, and is likely to change quite significantly in the near future.
Currently, all of the basic permissions explained above are provided in SELinux
as well; SELinux is simply invoked after all basic permission checks have been
performed.
The value of the file /proc/self/attr/keycreate influences the labeling of
newly-created keys. If the contents of that file correspond to an SELinux
security context, then the key will be assigned that context. Otherwise, the
key will be assigned the current context of the task that invoked the key
creation request. Tasks must be granted explicit permission to assign a
particular context to newly-created keys, using the "create" permission in the
key security class.
The default keyrings associated with users will be labeled with the default
context of the user if and only if the login programs have been instrumented to
properly initialize keycreate during the login process. Otherwise, they will
be labeled with the context of the login program itself.
Note, however, that the default keyrings associated with the root user are
labeled with the default kernel context, since they are created early in the
boot process, before root has a chance to log in.
The keyrings associated with new threads are each labeled with the context of
their associated thread, and both session and process keyrings are handled
similarly.
/proc/keys, key-users와 quota sysctl
271-352`/proc/keys`는 읽는 태스크가 View 권한을 가진 key만 type·description·permission과 함께 나열한다. payload 자체는 볼 수 없지만 요약 정보가 포함될 수 있다. possession 여부와 무관하게 View를 허용한 key만 대상이며 LSM 검사가 추가로 필터링한다. 표의 flag는 `I` instantiated, `R` revoked, `D` dead, `Q` quota 기여, `U` 사용자 공간 callback으로 construction 중, `N` negative를 뜻한다.
`/proc/key-users`는 적어도 하나의 key가 있는 사용자별 추적 자료를 보여 준다. 각 줄은 UID, 구조체 reference count, instantiated/전체 key 수, key 수 quota, byte quota를 기록한다.
root용 한도는 `/proc/sys/kernel/keys/root_maxkeys`와 `root_maxbytes`, non-root 사용자별 한도는 `maxkeys`와 `maxbytes`에 있다. root는 해당 파일에 새 10진 숫자 문자열을 써서 최대 key 수와 총 저장 바이트를 변경할 수 있다.
키 목록의 상태 표식이다.
New ProcFS Files
================
Two files have been added to procfs by which an administrator can find out
about the status of the key service:
* /proc/keys
This lists the keys that are currently viewable by the task reading the
file, giving information about their type, description and permissions.
It is not possible to view the payload of the key this way, though some
information about it may be given.
The only keys included in the list are those that grant View permission to
the reading process whether or not it possesses them. Note that LSM
security checks are still performed, and may further filter out keys that
the current process is not authorised to view.
The contents of the file look like this::
SERIAL FLAGS USAGE EXPY PERM UID GID TYPE DESCRIPTION: SUMMARY
00000001 I----- 39 perm 1f3f0000 0 0 keyring _uid_ses.0: 1/4
00000002 I----- 2 perm 1f3f0000 0 0 keyring _uid.0: empty
00000007 I----- 1 perm 1f3f0000 0 0 keyring _pid.1: empty
0000018d I----- 1 perm 1f3f0000 0 0 keyring _pid.412: empty
000004d2 I--Q-- 1 perm 1f3f0000 32 -1 keyring _uid.32: 1/4
000004d3 I--Q-- 3 perm 1f3f0000 32 -1 keyring _uid_ses.32: empty
00000892 I--QU- 1 perm 1f000000 0 0 user metal:copper: 0
00000893 I--Q-N 1 35s 1f3f0000 0 0 user metal:silver: 0
00000894 I--Q-- 1 10h 003f0000 0 0 user metal:gold: 0
The flags are::
I Instantiated
R Revoked
D Dead
Q Contributes to user's quota
U Under construction by callback to userspace
N Negative key
* /proc/key-users
This file lists the tracking data for each user that has at least one key
on the system. Such data includes quota information and statistics::
[root@andromeda root]# cat /proc/key-users
0: 46 45/45 1/100 13/10000
29: 2 2/2 2/100 40/10000
32: 2 2/2 2/100 40/10000
38: 2 2/2 2/100 40/10000
The format of each line is::
<UID>: User ID to which this applies
<usage> Structure refcount
<inst>/<keys> Total number of keys and number instantiated
<keys>/<max> Key count quota
<bytes>/<max> Key size quota
Four new sysctl files have been added also for the purpose of controlling the
quota limits on keys:
* /proc/sys/kernel/keys/root_maxkeys
/proc/sys/kernel/keys/root_maxbytes
These files hold the maximum number of keys that root may have and the
maximum total number of bytes of data that root may have stored in those
keys.
* /proc/sys/kernel/keys/maxkeys
/proc/sys/kernel/keys/maxbytes
These files hold the maximum number of keys that each non-root user may
have and the maximum total number of bytes of data that each of those
users may have stored in their keys.
Root may alter these by writing each new limit as a decimal number string to
the appropriate file.
특수 ID와 add_key()·request_key()
353-442사용자 공간은 `add_key`, `request_key`, `keyctl` 세 system call로 key를 직접 조작한다. 일반 key는 양의 32비트 serial로 참조하고, 음수 특수 ID `KEY_SPEC_THREAD_KEYRING`(-1), `PROCESS`(-2), `SESSION`(-3), `USER`(-4), `USER_SESSION`(-5), `GROUP`(-6), `REQKEY_AUTH_KEY`(-7)로 현재 프로세스 관련 keyring과 request authorization key를 가리킨다.
`add_key(type, desc, payload, plen, keyring)`는 동일 type·description key가 있으면 Write 권한 아래 update를 시도하며 type이 update를 지원하지 않으면 `EEXIST`다. 없으면 지정 type과 description으로 생성·instantiate하고 keyring에 붙이며 keyring Write가 필요하다. 새 key는 user 권한을 모두 받고 group·other 권한은 없다. type이 지원하면 비어 있는 description을 payload에서 만들 수 있고 payload는 선택적이다. `keyring` type과 NULL payload로 새 keyring, `user` type으로 user key를 만든다. user key description은 Kerberos TGT의 `krb5tgt:`처럼 type ID와 colon 접두사를 권장한다. 성공하면 새 key 또는 update된 key ID를 반환한다.
`request_key(type, description, callout_info, dest_keyring)`는 thread→process→session 순서로 keyring을 검색하며 `KEYCTL_SEARCH`와 같은 방식으로 선택적 destination link를 만든다. 찾지 못하고 callout 정보가 있으면 `/sbin/request-key`를 인자와 함께 실행한다. destination link에는 key의 Link와 keyring의 Write 권한이 모두 필요하며 자세한 내용은 `Documentation/security/keys/request-key.rst`에 있다.
현재 프로세스와 관련된 keyring을 음수 상수로 참조한다.
Userspace System Call Interface
===============================
Userspace can manipulate keys directly through three new syscalls: add_key,
request_key and keyctl. The latter provides a number of functions for
manipulating keys.
When referring to a key directly, userspace programs should use the key's
serial number (a positive 32-bit integer). However, there are some special
values available for referring to special keys and keyrings that relate to the
process making the call::
CONSTANT VALUE KEY REFERENCED
============================== ====== ===========================
KEY_SPEC_THREAD_KEYRING -1 thread-specific keyring
KEY_SPEC_PROCESS_KEYRING -2 process-specific keyring
KEY_SPEC_SESSION_KEYRING -3 session-specific keyring
KEY_SPEC_USER_KEYRING -4 UID-specific keyring
KEY_SPEC_USER_SESSION_KEYRING -5 UID-session keyring
KEY_SPEC_GROUP_KEYRING -6 GID-specific keyring
KEY_SPEC_REQKEY_AUTH_KEY -7 assumed request_key()
authorisation key
The main syscalls are:
* Create a new key of given type, description and payload and add it to the
nominated keyring::
key_serial_t add_key(const char *type, const char *desc,
const void *payload, size_t plen,
key_serial_t keyring);
If a key of the same type and description as that proposed already exists
in the keyring, this will try to update it with the given payload, or it
will return error EEXIST if that function is not supported by the key
type. The process must also have permission to write to the key to be able
to update it. The new key will have all user permissions granted and no
group or third party permissions.
Otherwise, this will attempt to create a new key of the specified type and
description, and to instantiate it with the supplied payload and attach it
to the keyring. In this case, an error will be generated if the process
does not have permission to write to the keyring.
If the key type supports it, if the description is NULL or an empty
string, the key type will try and generate a description from the content
of the payload.
The payload is optional, and the pointer can be NULL if not required by
the type. The payload is plen in size, and plen can be zero for an empty
payload.
A new keyring can be generated by setting type "keyring", the keyring name
as the description (or NULL) and setting the payload to NULL.
User defined keys can be created by specifying type "user". It is
recommended that a user defined key's description by prefixed with a type
ID and a colon, such as "krb5tgt:" for a Kerberos 5 ticket granting
ticket.
Any other type must have been registered with the kernel in advance by a
kernel service such as a filesystem.
The ID of the new or updated key is returned if successful.
* Search the process's keyrings for a key, potentially calling out to
userspace to create it::
key_serial_t request_key(const char *type, const char *description,
const char *callout_info,
key_serial_t dest_keyring);
This function searches all the process's keyrings in the order thread,
process, session for a matching key. This works very much like
KEYCTL_SEARCH, including the optional attachment of the discovered key to
a keyring.
If a key cannot be found, and if callout_info is not NULL, then
/sbin/request-key will be invoked in an attempt to obtain a key. The
callout_info string will be passed as an argument to the program.
To link a key into the destination keyring the key must grant link
permission on the key to the caller and the keyring must grant write
permission.
See also Documentation/security/keys/request-key.rst.
기본 keyctl 연산
443-550`KEYCTL_GET_KEYRING_ID`는 특수 ID를 실제 ID로 변환하며 key가 없을 때 `create`가 0이 아니면 만들고 0이면 `ENOKEY`다. `KEYCTL_JOIN_SESSION_KEYRING`은 이름이 NULL이면 익명 session keyring, 이름이 있으면 search 권한 아래 기존 ring에 join하거나 새 ring을 만들어 현재 session ring을 교체하고 ID를 반환한다.
`KEYCTL_UPDATE`는 Write 권한 아래 payload를 바꾸며 type이 지원하지 않으면 `EOPNOTSUPP`다. `KEYCTL_REVOKE`는 이후 연산을 `EKEYREVOKED`로 실패시키고 검색되지 않게 한다. `KEYCTL_CHOWN`은 owner·group을 바꾸고 -1은 해당 변경을 생략한다. superuser만 owner를 다른 UID로 바꿀 수 있고 group도 호출자의 group 또는 보조 group 밖으로 바꿀 수 있다. `KEYCTL_SETPERM`은 owner 또는 superuser가 정의된 bit만 설정하며 다른 bit는 `EINVAL`이다.
`KEYCTL_DESCRIBE`는 payload를 제외한 속성을 `<type>;<uid>;<gid>;<perm>;<description>` 문자열로 반환한다. buffer가 작아도 생성 가능한 전체 길이를 반환하고 요청 길이 이상 복사하지 않으며 NULL buffer면 복사하지 않는다. View 권한이 필요하고 충분한 buffer에는 NUL도 포함된다. 원문의 `sscanf()` parse 예제를 보존한다.
식별·session·payload·속성 조작 명령이다.
The keyctl syscall functions are:
* Map a special key ID to a real key ID for this process::
key_serial_t keyctl(KEYCTL_GET_KEYRING_ID, key_serial_t id,
int create);
The special key specified by "id" is looked up (with the key being created
if necessary) and the ID of the key or keyring thus found is returned if
it exists.
If the key does not yet exist, the key will be created if "create" is
non-zero; and the error ENOKEY will be returned if "create" is zero.
* Replace the session keyring this process subscribes to with a new one::
key_serial_t keyctl(KEYCTL_JOIN_SESSION_KEYRING, const char *name);
If name is NULL, an anonymous keyring is created attached to the process
as its session keyring, displacing the old session keyring.
If name is not NULL, if a keyring of that name exists, the process
attempts to attach it as the session keyring, returning an error if that
is not permitted; otherwise a new keyring of that name is created and
attached as the session keyring.
To attach to a named keyring, the keyring must have search permission for
the process's ownership.
The ID of the new session keyring is returned if successful.
* Update the specified key::
long keyctl(KEYCTL_UPDATE, key_serial_t key, const void *payload,
size_t plen);
This will try to update the specified key with the given payload, or it
will return error EOPNOTSUPP if that function is not supported by the key
type. The process must also have permission to write to the key to be able
to update it.
The payload is of length plen, and may be absent or empty as for
add_key().
* Revoke a key::
long keyctl(KEYCTL_REVOKE, key_serial_t key);
This makes a key unavailable for further operations. Further attempts to
use the key will be met with error EKEYREVOKED, and the key will no longer
be findable.
* Change the ownership of a key::
long keyctl(KEYCTL_CHOWN, key_serial_t key, uid_t uid, gid_t gid);
This function permits a key's owner and group ID to be changed. Either one
of uid or gid can be set to -1 to suppress that change.
Only the superuser can change a key's owner to something other than the
key's current owner. Similarly, only the superuser can change a key's
group ID to something other than the calling process's group ID or one of
its group list members.
* Change the permissions mask on a key::
long keyctl(KEYCTL_SETPERM, key_serial_t key, key_perm_t perm);
This function permits the owner of a key or the superuser to change the
permissions mask on a key.
Only bits the available bits are permitted; if any other bits are set,
error EINVAL will be returned.
* Describe a key::
long keyctl(KEYCTL_DESCRIBE, key_serial_t key, char *buffer,
size_t buflen);
This function returns a summary of the key's attributes (but not its
payload data) as a string in the buffer provided.
Unless there's an error, it always returns the amount of data it could
produce, even if that's too big for the buffer, but it won't copy more
than requested to userspace. If the buffer pointer is NULL then no copy
will take place.
A process must have view permission on the key for this function to be
successful.
If successful, a string is placed in the buffer in the following format::
<type>;<uid>;<gid>;<perm>;<description>
Where type and description are strings, uid and gid are decimal, and perm
is hexadecimal. A NUL character is included at the end of the string if
the buffer is sufficiently big.
This can be parsed with::
sscanf(buffer, "%[^;];%d;%d;%o;%s", type, &uid, &gid, &mode, desc);
keyring clear·link·move·unlink·search
551-640`KEYCTL_CLEAR`는 Write 권한 아래 keyring의 모든 링크를 지우며 keyring이 아니면 `ENOTDIR`다. 적절히 표시된 DNS resolver cache 같은 특수 커널 keyring도 `CAP_SYS_ADMIN`으로 비울 수 있다. `KEYCTL_LINK`는 keyring Write와 key Link 권한으로 링크를 만든다. keyring이 아니면 `ENOTDIR`, 가득 차면 `ENFILE`, 중첩이 너무 깊으면 `ELOOP`, cycle을 만들면 `EDEADLK`다. 같은 type·description의 기존 링크는 새 key를 추가하며 제거된다.
`KEYCTL_MOVE`는 source ring에서 destination ring으로 key를 옮기며 두 ring이 같으면 아무 일도 하지 않는다. `KEYCTL_MOVE_EXCL`이면 destination의 일치 key에 `EEXIST`, 아니면 교체한다. key Link와 두 keyring의 Write가 필요하고 destination에는 LINK 오류가 적용된다. `KEYCTL_UNLINK`는 첫 링크 하나만 제거하며 Write가 필요하고 keyring이 아니면 `ENOTDIR`, 링크가 없으면 `ENOENT`다.
`KEYCTL_SEARCH`는 지정 keyring에서 먼저 현재 ring의 key를 검사한 뒤 자식으로 재귀해 type·description을 찾는다. top-level과 재귀할 각 ring 및 일치할 key에 Search 권한이 필요하다. destination이 0이 아니면 LINK 조건 아래 결과를 붙인다. 실패에 따라 `ENOKEY`, `EKEYREVOKED`, `EKEYEXPIRED`, 성공 시 key ID를 반환한다.
권한이 있는 ring만 작성된 트리 순서로 내려간다.
* Clear out a keyring::
long keyctl(KEYCTL_CLEAR, key_serial_t keyring);
This function clears the list of keys attached to a keyring. The calling
process must have write permission on the keyring, and it must be a
keyring (or else error ENOTDIR will result).
This function can also be used to clear special kernel keyrings if they
are appropriately marked if the user has CAP_SYS_ADMIN capability. The
DNS resolver cache keyring is an example of this.
* Link a key into a keyring::
long keyctl(KEYCTL_LINK, key_serial_t keyring, key_serial_t key);
This function creates a link from the keyring to the key. The process must
have write permission on the keyring and must have link permission on the
key.
Should the keyring not be a keyring, error ENOTDIR will result; and if the
keyring is full, error ENFILE will result.
The link procedure checks the nesting of the keyrings, returning ELOOP if
it appears too deep or EDEADLK if the link would introduce a cycle.
Any links within the keyring to keys that match the new key in terms of
type and description will be discarded from the keyring as the new one is
added.
* Move a key from one keyring to another::
long keyctl(KEYCTL_MOVE,
key_serial_t id,
key_serial_t from_ring_id,
key_serial_t to_ring_id,
unsigned int flags);
Move the key specified by "id" from the keyring specified by
"from_ring_id" to the keyring specified by "to_ring_id". If the two
keyrings are the same, nothing is done.
"flags" can have KEYCTL_MOVE_EXCL set in it to cause the operation to fail
with EEXIST if a matching key exists in the destination keyring, otherwise
such a key will be replaced.
A process must have link permission on the key for this function to be
successful and write permission on both keyrings. Any errors that can
occur from KEYCTL_LINK also apply on the destination keyring here.
* Unlink a key or keyring from another keyring::
long keyctl(KEYCTL_UNLINK, key_serial_t keyring, key_serial_t key);
This function looks through the keyring for the first link to the
specified key, and removes it if found. Subsequent links to that key are
ignored. The process must have write permission on the keyring.
If the keyring is not a keyring, error ENOTDIR will result; and if the key
is not present, error ENOENT will be the result.
* Search a keyring tree for a key::
key_serial_t keyctl(KEYCTL_SEARCH, key_serial_t keyring,
const char *type, const char *description,
key_serial_t dest_keyring);
This searches the keyring tree headed by the specified keyring until a key
is found that matches the type and description criteria. Each keyring is
checked for keys before recursion into its children occurs.
The process must have search permission on the top level keyring, or else
error EACCES will result. Only keyrings that the process has search
permission on will be recursed into, and only keys and keyrings for which
a process has search permission can be matched. If the specified keyring
is not a keyring, ENOTDIR will result.
If the search succeeds, the function will attempt to link the found key
into the destination keyring if one is supplied (non-zero ID). All the
constraints applicable to KEYCTL_LINK apply in this case too.
Error ENOKEY, EKEYREVOKED or EKEYEXPIRED will be returned if the search
fails. On success, the resulting key ID will be returned.
payload read와 positive·negative instantiate
641-712`KEYCTL_READ`는 Read 권한 아래 type별 표현으로 payload를 buffer에 쓴다. keyring은 연결 key ID의 `key_serial_t` 배열, user type은 원본 데이터를 반환한다. type이 read를 구현하지 않으면 `EOPNOTSUPP`다. buffer가 작으면 필요 크기를 반환하지만 buffer 내용은 정의되지 않게 덮일 수 있고, 성공 시 복사 바이트 수를 반환한다.
사용자 공간 callback으로 부분 생성 key를 완성할 때 `KEYCTL_INSTANTIATE` 또는 iovec 버전 `KEYCTL_INSTANTIATE_IOV`를 호출한다. callback 프로세스가 돌아오기 전에 payload를 제공하지 않으면 자동으로 negative가 된다. uninstantiated key에 대한 Write가 필요하고 destination keyring이 있으면 LINK 제약도 적용된다. 단일 buffer는 `payload`·`plen`, 배열은 `payload_iov`·`ioc`로 설명한다.
요청을 충족할 수 없으면 `KEYCTL_NEGATE` 또는 `KEYCTL_REJECT`로 negative instantiate한다. Write와 uninstantiated 상태가 필요하며 선택적 keyring link도 같은 제약을 따른다. reject된 key는 timeout까지 지정 error를 검색 결과로 돌려주고, negate는 error가 `ENOKEY`인 reject와 같다.
callback은 성공 또는 실패 상태를 명시해야 한다.
* Read the payload data from a key::
long keyctl(KEYCTL_READ, key_serial_t keyring, char *buffer,
size_t buflen);
This function attempts to read the payload data from the specified key
into the buffer. The process must have read permission on the key to
succeed.
The returned data will be processed for presentation by the key type. For
instance, a keyring will return an array of key_serial_t entries
representing the IDs of all the keys to which it is subscribed. The user
defined key type will return its data as is. If a key type does not
implement this function, error EOPNOTSUPP will result.
If the specified buffer is too small, then the size of the buffer required
will be returned. Note that in this case, the contents of the buffer may
have been overwritten in some undefined way.
Otherwise, on success, the function will return the amount of data copied
into the buffer.
* Instantiate a partially constructed key::
long keyctl(KEYCTL_INSTANTIATE, key_serial_t key,
const void *payload, size_t plen,
key_serial_t keyring);
long keyctl(KEYCTL_INSTANTIATE_IOV, key_serial_t key,
const struct iovec *payload_iov, unsigned ioc,
key_serial_t keyring);
If the kernel calls back to userspace to complete the instantiation of a
key, userspace should use this call to supply data for the key before the
invoked process returns, or else the key will be marked negative
automatically.
The process must have write access on the key to be able to instantiate
it, and the key must be uninstantiated.
If a keyring is specified (non-zero), the key will also be linked into
that keyring, however all the constraints applying in KEYCTL_LINK apply in
this case too.
The payload and plen arguments describe the payload data as for add_key().
The payload_iov and ioc arguments describe the payload data in an iovec
array instead of a single buffer.
* Negatively instantiate a partially constructed key::
long keyctl(KEYCTL_NEGATE, key_serial_t key,
unsigned timeout, key_serial_t keyring);
long keyctl(KEYCTL_REJECT, key_serial_t key,
unsigned timeout, unsigned error, key_serial_t keyring);
If the kernel calls back to userspace to complete the instantiation of a
key, userspace should use this call mark the key as negative before the
invoked process returns if it is unable to fulfill the request.
The process must have write access on the key to be able to instantiate
it, and the key must be uninstantiated.
If a keyring is specified (non-zero), the key will also be linked into
that keyring, however all the constraints applying in KEYCTL_LINK apply in
this case too.
If the key is rejected, future searches for it will return the specified
error code until the rejected key expires. Negating the key is the same
as rejecting the key with ENOKEY as the error code.
request destination, timeout과 authority
713-778`KEYCTL_SET_REQKEY_KEYRING`은 이 thread가 암묵적으로 요청한 key를 붙일 기본 ring을 정한다. 상수는 NO_CHANGE(-1), DEFAULT(0), THREAD(1), PROCESS(2), SESSION(3), USER(4), USER_SESSION(5), GROUP(6)이며 성공하면 이전 기본값, 잘못된 값이면 `EINVAL`이다. `request_key()`의 destination이 이를 덮어쓸 수 있고 설정은 fork·exec를 넘어 상속된다. DEFAULT는 존재하는 thread→process→session→user default session 순서다.
`KEYCTL_SET_TIMEOUT`은 Set Attribute 권한 아래 0으로 timeout을 지우거나 초 단위 미래 expiry를 설정한다. negative·revoked·expired key에는 설정할 수 없다.
`KEYCTL_ASSUME_AUTHORITY`는 특정 key를 instantiate할 권한을 취하거나 내려놓는다. thread keyring 어딘가에 해당 authorization key가 있어야 한다. authority를 취하면 requester의 security label, UID, GID, groups로 requester keyring도 검색한다. 없거나 target이 이미 instantiated되어 authority가 revoke됐으면 `EPERM`; key 0은 현재 authority를 내려놓는다. authority key는 fork와 exec를 넘어 상속된다.
암묵적 요청 결과를 붙일 위치 상수다.
* Set the default request-key destination keyring::
long keyctl(KEYCTL_SET_REQKEY_KEYRING, int reqkey_defl);
This sets the default keyring to which implicitly requested keys will be
attached for this thread. reqkey_defl should be one of these constants::
CONSTANT VALUE NEW DEFAULT KEYRING
====================================== ====== =======================
KEY_REQKEY_DEFL_NO_CHANGE -1 No change
KEY_REQKEY_DEFL_DEFAULT 0 Default[1]
KEY_REQKEY_DEFL_THREAD_KEYRING 1 Thread keyring
KEY_REQKEY_DEFL_PROCESS_KEYRING 2 Process keyring
KEY_REQKEY_DEFL_SESSION_KEYRING 3 Session keyring
KEY_REQKEY_DEFL_USER_KEYRING 4 User keyring
KEY_REQKEY_DEFL_USER_SESSION_KEYRING 5 User session keyring
KEY_REQKEY_DEFL_GROUP_KEYRING 6 Group keyring
The old default will be returned if successful and error EINVAL will be
returned if reqkey_defl is not one of the above values.
The default keyring can be overridden by the keyring indicated to the
request_key() system call.
Note that this setting is inherited across fork/exec.
[1] The default is: the thread keyring if there is one, otherwise
the process keyring if there is one, otherwise the session keyring if
there is one, otherwise the user default session keyring.
* Set the timeout on a key::
long keyctl(KEYCTL_SET_TIMEOUT, key_serial_t key, unsigned timeout);
This sets or clears the timeout on a key. The timeout can be 0 to clear
the timeout or a number of seconds to set the expiry time that far into
the future.
The process must have attribute modification access on a key to set its
timeout. Timeouts may not be set with this function on negative, revoked
or expired keys.
* Assume the authority granted to instantiate a key::
long keyctl(KEYCTL_ASSUME_AUTHORITY, key_serial_t key);
This assumes or divests the authority required to instantiate the
specified key. Authority can only be assumed if the thread has the
authorisation key associated with the specified key in its keyrings
somewhere.
Once authority is assumed, searches for keys will also search the
requester's keyrings using the requester's security label, UID, GID and
groups.
If the requested authority is unavailable, error EPERM will be returned,
likewise if the authority has been revoked because the target key is
already instantiated.
If the specified key is 0, then any assumed authority will be divested.
The assumed authoritative key is inherited across fork and exec.
LSM context, parent session과 invalidate
779-835`KEYCTL_GET_SECURITY`는 key에 붙은 LSM security context 문자열을 반환한다. buffer 크기보다 커도 생성 가능한 전체 크기를 반환하고 NULL이면 복사하지 않는다. 충분한 buffer에서는 NUL이 반환 count에 포함되며 LSM이 없으면 빈 문자열이다. View 권한이 필요하다.
`KEYCTL_SESSION_TO_PARENT`는 호출 프로세스의 session keyring을 parent에 설치해 기존 ring을 교체한다. parent와 caller의 ownership이 같고 keyring도 caller 소유이며 caller에게 Link 권한이 있고 LSM이 허용해야 한다. 위반은 `EPERM`, 메모리 부족은 `ENOMEM`, 성공은 0이며 parent가 다음에 커널에서 사용자 공간으로 돌아갈 때 교체된다.
`KEYCTL_INVALIDATE`는 key를 invalidated로 표시하고 garbage collector를 깨운다. collector는 모든 keyring에서 즉시 unlink하고 reference count가 0이면 삭제한다. 일반 연산에는 즉시 보이지 않지만 삭제 전 `/proc/keys`에는 `i` flag로 남는다. Search 권한이 필요하다.
* Get the LSM security context attached to a key::
long keyctl(KEYCTL_GET_SECURITY, key_serial_t key, char *buffer,
size_t buflen)
This function returns a string that represents the LSM security context
attached to a key in the buffer provided.
Unless there's an error, it always returns the amount of data it could
produce, even if that's too big for the buffer, but it won't copy more
than requested to userspace. If the buffer pointer is NULL then no copy
will take place.
A NUL character is included at the end of the string if the buffer is
sufficiently big. This is included in the returned count. If no LSM is
in force then an empty string will be returned.
A process must have view permission on the key for this function to be
successful.
* Install the calling process's session keyring on its parent::
long keyctl(KEYCTL_SESSION_TO_PARENT);
This functions attempts to install the calling process's session keyring
on to the calling process's parent, replacing the parent's current session
keyring.
The calling process must have the same ownership as its parent, the
keyring must have the same ownership as the calling process, the calling
process must have LINK permission on the keyring and the active LSM module
mustn't deny permission, otherwise error EPERM will be returned.
Error ENOMEM will be returned if there was insufficient memory to complete
the operation, otherwise 0 will be returned to indicate success.
The keyring will be replaced next time the parent process leaves the
kernel and resumes executing userspace.
* Invalidate a key::
long keyctl(KEYCTL_INVALIDATE, key_serial_t key);
This function marks a key as being invalidated and then wakes up the
garbage collector. The garbage collector immediately removes invalidated
keys from all keyrings and deletes the key when its reference count
reaches zero.
Keys that are marked invalidated become invisible to normal key operations
immediately, though they are still visible in /proc/keys until deleted
(they're marked with an 'i' flag).
A process must have search permission on the key for this function to be
successful.
Diffie-Hellman과 KDF
836-887`KEYCTL_DH_COMPUTE`는 prime `p`, local private key, shared generator 또는 remote public key인 base의 세 key serial로 `base ^ private (mod prime)`을 계산한다. base가 generator면 local public key, remote public key면 shared secret이다.
`kdf`가 NULL이면 buffer는 prime 길이 이상이거나 길이 0이어야 한다. 0이 아니면 계산·복사한 결과 길이, 0이면 최소 buffer 길이를 반환한다. `struct keyctl_kdf_params`를 주면 호출자에게 DH 원값 대신 KDF 결과만 반환한다. NUL 종료 `hashname`은 kernel crypto API hash를 정하고 SP800-56A와 SP800-108 counter KDF를 따른다. `otherinfo`와 `otherinfolen`은 SP800-56A 5.8.1.2의 caller-defined OtherInfo이며 사용하지 않으면 NULL이다.
지원하지 않는 type은 `EOPNOTSUPP`, key 없음은 `ENOKEY`, Read 불가는 `EACCES`다. kdf 사용 시 buffer 또는 OtherInfo 길이가 한도를 넘으면 `EMSGSIZE`다.
base의 종류에 따라 public key 또는 shared secret을 얻고 선택적으로 KDF를 적용한다.
* Compute a Diffie-Hellman shared secret or public key::
long keyctl(KEYCTL_DH_COMPUTE, struct keyctl_dh_params *params,
char *buffer, size_t buflen, struct keyctl_kdf_params *kdf);
The params struct contains serial numbers for three keys::
- The prime, p, known to both parties
- The local private key
- The base integer, which is either a shared generator or the
remote public key
The value computed is::
result = base ^ private (mod prime)
If the base is the shared generator, the result is the local
public key. If the base is the remote public key, the result is
the shared secret.
If the parameter kdf is NULL, the following applies:
- The buffer length must be at least the length of the prime, or zero.
- If the buffer length is nonzero, the length of the result is
returned when it is successfully calculated and copied in to the
buffer. When the buffer length is zero, the minimum required
buffer length is returned.
The kdf parameter allows the caller to apply a key derivation function
(KDF) on the Diffie-Hellman computation where only the result
of the KDF is returned to the caller. The KDF is characterized with
struct keyctl_kdf_params as follows:
- ``char *hashname`` specifies the NUL terminated string identifying
the hash used from the kernel crypto API and applied for the KDF
operation. The KDF implementation complies with SP800-56A as well
as with SP800-108 (the counter KDF).
- ``char *otherinfo`` specifies the OtherInfo data as documented in
SP800-56A section 5.8.1.2. The length of the buffer is given with
otherinfolen. The format of OtherInfo is defined by the caller.
The otherinfo pointer may be NULL if no OtherInfo shall be used.
This function will return error EOPNOTSUPP if the key type is not
supported, error ENOKEY if the key could not be found, or error
EACCES if the key is not readable by the caller. In addition, the
function will return EMSGSIZE when the parameter kdf is non-NULL
and either the buffer length or the OtherInfo length exceeds the
allowed length.
KEYCTL_RESTRICT_KEYRING
888-918`KEYCTL_RESTRICT_KEYRING`은 기존 keyring에 앞으로 연결할 key를 restriction scheme으로 제한한다. 기존 링크는 새 제한에 맞지 않아도 유지된다. `type`은 등록된 key type이고 `restriction` 문자열 형식은 type마다 다르며 해당 type의 `lookup_restriction()`에 전달된다. 서명 검증 방식이나 payload 제약을 지정할 수 있다. 이후 type이 unregister되면 새 key를 더 추가할 수 없다.
restriction 적용에는 Set Attribute 권한이 필요하고 이미 제한된 keyring에는 다시 적용할 수 없다. 대표 용도는 asymmetric key type으로 X.509 certificate chain 또는 개별 서명을 검증하는 것이며 세부 제약은 `Documentation/crypto/asymmetric-keys.rst`에 있다.
* Restrict keyring linkage::
long keyctl(KEYCTL_RESTRICT_KEYRING, key_serial_t keyring,
const char *type, const char *restriction);
An existing keyring can restrict linkage of additional keys by evaluating
the contents of the key according to a restriction scheme.
"keyring" is the key ID for an existing keyring to apply a restriction
to. It may be empty or may already have keys linked. Existing linked keys
will remain in the keyring even if the new restriction would reject them.
"type" is a registered key type.
"restriction" is a string describing how key linkage is to be restricted.
The format varies depending on the key type, and the string is passed to
the lookup_restriction() function for the requested type. It may specify
a method and relevant data for the restriction such as signature
verification or constraints on key payload. If the requested key type is
later unregistered, no keys may be added to the keyring after the key type
is removed.
To apply a keyring restriction the process must have Set Attribute
permission and the keyring must not be previously restricted.
One application of restricted keyrings is to verify X.509 certificate
chains or individual certificate signatures using the asymmetric key type.
See Documentation/crypto/asymmetric-keys.rst for specific restrictions
applicable to the asymmetric key type.
Asymmetric key 조회와 암호 연산
919-1032`KEYCTL_PKEY_QUERY`는 asymmetric key의 알고리즘·encoding 정보를 `params`의 공백 또는 tab 구분 key-value(`enc`, `hash`)로 질의한다. 결과 `keyctl_pkey_query`에는 supported operation bitmask, bit 단위 key size, sign data·signature·encrypt·decrypt 최대 byte 크기와 미래 passphrase 전달용 0으로 채운 `__spare[10]`이 있다. operation bit는 `KEYCTL_SUPPORTS_{ENCRYPT,DECRYPT,SIGN,VERIFY}`의 OR다. 성공 0, asymmetric key가 아니면 `EOPNOTSUPP`다.
`KEYCTL_PKEY_ENCRYPT`, `DECRYPT`, `SIGN`, `VERIFY`는 `keyctl_pkey_params`의 key ID와 input/output/second input 길이를 사용한다. encrypt는 raw→encrypted, decrypt는 encrypted→raw, sign은 raw→signature, verify는 raw와 두 번째 signature를 비교한다. encrypt·verify는 public 부분만으로 가능할 수 있지만 decrypt·sign에는 private 부분도 필요하다.
`info`의 `enc=`는 `pkcs1`(RSASSA/RSAES-PKCS1-v1.5), `pss`(RSASSA-PSS), `oaep`(RSAES-OAEP), 생략 또는 `raw`를 정한다. `hash=`는 입력이 hash 결과이고 encoding이 hash 종류를 담을 때 `sha256` 같은 알고리즘을 지정한다. parameter spare는 0이어야 한다. encrypt·decrypt·sign은 output byte 수, verify는 성공 0을 반환한다.
operation별 입력·출력·두 번째 입력의 의미다.
* Query an asymmetric key::
long keyctl(KEYCTL_PKEY_QUERY,
key_serial_t key_id, unsigned long reserved,
const char *params,
struct keyctl_pkey_query *info);
Get information about an asymmetric key. Specific algorithms and
encodings may be queried by using the ``params`` argument. This is a
string containing a space- or tab-separated string of key-value pairs.
Currently supported keys include ``enc`` and ``hash``. The information
is returned in the keyctl_pkey_query struct::
__u32 supported_ops;
__u32 key_size;
__u16 max_data_size;
__u16 max_sig_size;
__u16 max_enc_size;
__u16 max_dec_size;
__u32 __spare[10];
``supported_ops`` contains a bit mask of flags indicating which ops are
supported. This is constructed from a bitwise-OR of::
KEYCTL_SUPPORTS_{ENCRYPT,DECRYPT,SIGN,VERIFY}
``key_size`` indicated the size of the key in bits.
``max_*_size`` indicate the maximum sizes in bytes of a blob of data to be
signed, a signature blob, a blob to be encrypted and a blob to be
decrypted.
``__spare[]`` must be set to 0. This is intended for future use to hand
over one or more passphrases needed unlock a key.
If successful, 0 is returned. If the key is not an asymmetric key,
EOPNOTSUPP is returned.
* Encrypt, decrypt, sign or verify a blob using an asymmetric key::
long keyctl(KEYCTL_PKEY_ENCRYPT,
const struct keyctl_pkey_params *params,
const char *info,
const void *in,
void *out);
long keyctl(KEYCTL_PKEY_DECRYPT,
const struct keyctl_pkey_params *params,
const char *info,
const void *in,
void *out);
long keyctl(KEYCTL_PKEY_SIGN,
const struct keyctl_pkey_params *params,
const char *info,
const void *in,
void *out);
long keyctl(KEYCTL_PKEY_VERIFY,
const struct keyctl_pkey_params *params,
const char *info,
const void *in,
const void *in2);
Use an asymmetric key to perform a public-key cryptographic operation a
blob of data. For encryption and verification, the asymmetric key may
only need the public parts to be available, but for decryption and signing
the private parts are required also.
The parameter block pointed to by params contains a number of integer
values::
__s32 key_id;
__u32 in_len;
__u32 out_len;
__u32 in2_len;
``key_id`` is the ID of the asymmetric key to be used. ``in_len`` and
``in2_len`` indicate the amount of data in the in and in2 buffers and
``out_len`` indicates the size of the out buffer as appropriate for the
above operations.
For a given operation, the in and out buffers are used as follows::
Operation ID in,in_len out,out_len in2,in2_len
======================= =============== =============== ===============
KEYCTL_PKEY_ENCRYPT Raw data Encrypted data -
KEYCTL_PKEY_DECRYPT Encrypted data Raw data -
KEYCTL_PKEY_SIGN Raw data Signature -
KEYCTL_PKEY_VERIFY Raw data - Signature
``info`` is a string of key=value pairs that supply supplementary
information. These include:
``enc=<encoding>`` The encoding of the encrypted/signature blob. This
can be "pkcs1" for RSASSA-PKCS1-v1.5 or
RSAES-PKCS1-v1.5; "pss" for "RSASSA-PSS"; "oaep" for
"RSAES-OAEP". If omitted or is "raw", the raw output
of the encryption function is specified.
``hash=<algo>`` If the data buffer contains the output of a hash
function and the encoding includes some indication of
which hash function was used, the hash function can be
specified with this, eg. "hash=sha256".
The ``__spare[]`` space in the parameter block must be set to 0. This is
intended, amongst other things, to allow the passing of passphrases
required to unlock a key.
If successful, encrypt, decrypt and sign all return the amount of data
written into the output buffer. Verification returns 0 on success.
Key 변경 notification
1033-1089`KEYCTL_WATCH_KEY`는 특정 key 또는 keyring 변경 watch를 설치하거나 제거한다. `key`는 대상 ID, `queue_fd`는 notification buffer를 관리하는 열린 pipe FD, `filter`는 필요한 event 지정 또는 watch 제거용 NULL이다. 자세한 watch queue는 `Documentation/core-api/watch_queue.rst`에 있으며 `{key, queue_fd}` 조합마다 하나만 설치할 수 있다.
`struct key_notification`은 기본 `watch_notification`, `key_id`, `aux`를 담는다. type은 `WATCH_TYPE_KEY_NOTIFY`, subtype은 INSTANTIATED, UPDATED, LINKED, UNLINKED, CLEARED, REVOKED, INVALIDATED, SETATTR 중 하나다. SETATTR에는 user·group·perm·timeout·restriction 변경이 포함된다. watched key 삭제 시 `WATCH_TYPE_META`와 `watch_meta_removal_notification`, info의 watchpoint ID를 보낸다. `KEY_NOTIFICATIONS` 설정이 필요하다.
watch가 보고하는 변경 종류다.
* Watch a key or keyring for changes::
long keyctl(KEYCTL_WATCH_KEY, key_serial_t key, int queue_fd,
const struct watch_notification_filter *filter);
This will set or remove a watch for changes on the specified key or
keyring.
"key" is the ID of the key to be watched.
"queue_fd" is a file descriptor referring to an open pipe which
manages the buffer into which notifications will be delivered.
"filter" is either NULL to remove a watch or a filter specification to
indicate what events are required from the key.
See Documentation/core-api/watch_queue.rst for more information.
Note that only one watch may be emplaced for any particular { key,
queue_fd } combination.
Notification records look like::
struct key_notification {
struct watch_notification watch;
__u32 key_id;
__u32 aux;
};
In this, watch::type will be "WATCH_TYPE_KEY_NOTIFY" and subtype will be
one of::
NOTIFY_KEY_INSTANTIATED
NOTIFY_KEY_UPDATED
NOTIFY_KEY_LINKED
NOTIFY_KEY_UNLINKED
NOTIFY_KEY_CLEARED
NOTIFY_KEY_REVOKED
NOTIFY_KEY_INVALIDATED
NOTIFY_KEY_SETATTR
Where these indicate a key being instantiated/rejected, updated, a link
being made in a keyring, a link being removed from a keyring, a keyring
being cleared, a key being revoked, a key being invalidated or a key
having one of its attributes changed (user, group, perm, timeout,
restriction).
If a watched key is deleted, a basic watch_notification will be issued
with "type" set to WATCH_TYPE_META and "subtype" set to
watch_meta_removal_notification. The watchpoint ID will be set in the
"info" field.
This needs to be configured by enabling:
"Provide key/keyring change notifications" (KEY_NOTIFICATIONS)
커널 포인터와 possession
1090-1143커널 서비스는 key type을 등록하고 해당 type key를 검색해 필요한 동안 참조를 유지한 뒤 해제한다. 파일 시스템이나 device file은 보통 open 때 검색하고 close 때 해제한다. 서로 다른 사용자가 같은 파일을 열어 충돌하는 key를 제공할 때의 해결은 파일 시스템 작성자의 책임이다. 기본 API는 `<linux/key.h>`, type별 API는 `include/keys/` 아래 header를 사용하며 user type은 `<keys/user-type.h>`다.
`struct key *`는 최소 4바이트 정렬의 실제 key 포인터다. `key_ref_t`는 동등한 포인터의 최하위 bit에 caller가 key를 `possess`하는지를 기록한다. possession은 프로세스 keyring 중 하나에서 검색 가능한 링크가 있다는 뜻이다. `make_key_ref()`는 포인터와 bool로 reference를 만들고, `key_ref_to_ptr()`는 포인터, `is_key_possessed()`는 flag를 얻는다. payload 접근은 수정 경합을 막는 별도 규칙을 따라야 한다.
key_ref_t는 정렬 여유 bit에 possession을 함께 운반한다.
Kernel Services
===============
The kernel services for key management are fairly simple to deal with. They can
be broken down into two areas: keys and key types.
Dealing with keys is fairly straightforward. Firstly, the kernel service
registers its type, then it searches for a key of that type. It should retain
the key as long as it has need of it, and then it should release it. For a
filesystem or device file, a search would probably be performed during the open
call, and the key released upon close. How to deal with conflicting keys due to
two different users opening the same file is left to the filesystem author to
solve.
To access the key manager, the following header must be #included::
<linux/key.h>
Specific key types should have a header file under include/keys/ that should be
used to access that type. For keys of type "user", for example, that would be::
<keys/user-type.h>
Note that there are two different types of pointers to keys that may be
encountered:
* struct key *
This simply points to the key structure itself. Key structures will be at
least four-byte aligned.
* key_ref_t
This is equivalent to a ``struct key *``, but the least significant bit is set
if the caller "possesses" the key. By "possession" it is meant that the
calling processes has a searchable link to the key from one of its
keyrings. There are three functions for dealing with these::
key_ref_t make_key_ref(const struct key *key, bool possession);
struct key *key_ref_to_ptr(const key_ref_t key_ref);
bool is_key_possessed(const key_ref_t key_ref);
The first function constructs a key reference from a key pointer and
possession information (which must be true or false).
The second function retrieves the key pointer from a reference and the
third retrieves the possession flag.
When accessing a key's payload contents, certain precautions must be taken to
prevent access vs modification races. See the section "Notes on accessing
payload contents" for more information.
커널 request_key 계열
1144-1203커널 `request_key(type, description, callout_info)`는 type의 `match_preparse()` 규칙으로 description을 검색해 근사 match도 허용한다. callout 정보가 있으면 `/sbin/request-key`로 사용자 공간에서 key를 얻고, 실패는 `ENOKEY`, `EKEYEXPIRED`, `EKEYREVOKED`다. 성공 결과는 `KEYCTL_SET_REQKEY_KEYRING`으로 정한 암묵적 기본 keyring에 붙는다.
`request_key_tag()`는 동일하지만 `domain_tag`와 일치하는 key만 찾는다. NULL tag는 지정 domain들과 분리된 global domain이다. `request_key_with_auxdata()`는 callout 정보를 길이 있는 blob으로 받고 `key_type->request_key()`에 aux를 전달한다.
`request_key_rcu()`는 RCU 조건에서 domain 검색을 하지만 construction 중 key를 검사하지 않고, 찾지 못해도 사용자 공간을 호출해 만들지 않는다.
* To search for a key, call::
struct key *request_key(const struct key_type *type,
const char *description,
const char *callout_info);
This is used to request a key or keyring with a description that matches
the description specified according to the key type's match_preparse()
method. This permits approximate matching to occur. If callout_string is
not NULL, then /sbin/request-key will be invoked in an attempt to obtain
the key from userspace. In that case, callout_string will be passed as an
argument to the program.
Should the function fail error ENOKEY, EKEYEXPIRED or EKEYREVOKED will be
returned.
If successful, the key will have been attached to the default keyring for
implicitly obtained request-key keys, as set by KEYCTL_SET_REQKEY_KEYRING.
See also Documentation/security/keys/request-key.rst.
* To search for a key in a specific domain, call::
struct key *request_key_tag(const struct key_type *type,
const char *description,
struct key_tag *domain_tag,
const char *callout_info);
This is identical to request_key(), except that a domain tag may be
specifies that causes search algorithm to only match keys matching that
tag. The domain_tag may be NULL, specifying a global domain that is
separate from any nominated domain.
* To search for a key, passing auxiliary data to the upcaller, call::
struct key *request_key_with_auxdata(const struct key_type *type,
const char *description,
struct key_tag *domain_tag,
const void *callout_info,
size_t callout_len,
void *aux);
This is identical to request_key_tag(), except that the auxiliary data is
passed to the key_type->request_key() op if it exists, and the
callout_info is a blob of length callout_len, if given (the length may be
0).
* To search for a key under RCU conditions, call::
struct key *request_key_rcu(const struct key_type *type,
const char *description,
struct key_tag *domain_tag);
which is similar to request_key_tag() except that it does not check for
keys that are under construction and it will not call out to userspace to
construct a key if it can't find a match.
커널 참조 수명과 keyring_search()
1204-1254더 이상 필요 없는 `struct key *`는 `key_put()`, `key_ref_t`는 `key_ref_put()`으로 해제하며 interrupt context에서도 호출할 수 있다. `CONFIG_KEYS`가 없으면 인자도 parse하지 않는다. `__key_get()`과 `key_get()`은 추가 reference를 만들고 반환 포인터를 돌려주며 나중에 `key_put()`이 필요하다. `key_get()`은 NULL이거나 CONFIG_KEYS가 없으면 dereference·증가하지 않는다. `key_serial()`은 serial을 반환하고 NULL 또는 비활성 설정이면 0이다.
`keyring_search(keyring_ref, type, description, recurse)`는 지정 ring만 또는 전체 tree에서 일치 key를 찾는다. 실패는 `ERR_PTR(ENOKEY)`이므로 `IS_ERR/PTR_ERR`를 사용하고 성공 reference는 해제해야 한다. 입력 keyring reference의 possession이 permission mask 접근에 쓰이고 성공 결과에도 전파된다.
* When it is no longer required, the key should be released using::
void key_put(struct key *key);
Or::
void key_ref_put(key_ref_t key_ref);
These can be called from interrupt context. If CONFIG_KEYS is not set then
the argument will not be parsed.
* Extra references can be made to a key by calling one of the following
functions::
struct key *__key_get(struct key *key);
struct key *key_get(struct key *key);
Keys so references will need to be disposed of by calling key_put() when
they've been finished with. The key pointer passed in will be returned.
In the case of key_get(), if the pointer is NULL or CONFIG_KEYS is not set
then the key will not be dereferenced and no increment will take place.
* A key's serial number can be obtained by calling::
key_serial_t key_serial(struct key *key);
If key is NULL or if CONFIG_KEYS is not set then 0 will be returned (in the
latter case without parsing the argument).
* If a keyring was found in the search, this can be further searched by::
key_ref_t keyring_search(key_ref_t keyring_ref,
const struct key_type *type,
const char *description,
bool recurse)
This searches the specified keyring only (recurse == false) or keyring tree
(recurse == true) specified for a matching key. Error ENOKEY is returned
upon failure (use IS_ERR/PTR_ERR to determine). If successful, the returned
key will need to be released.
The possession attribute from the keyring reference is used to control
access through the permissions mask and is propagated to the returned key
reference pointer if successful.
keyring_alloc(), validity와 type 등록
1255-1327`keyring_alloc()`은 description·UID·GID·cred·permission·link restriction·flags로 keyring을 만든다. `dest`가 있으면 permission 검사 없이 destination ring에 link한다. quota 초과는 `EDQUOT`, 메모리 부족은 `ENOMEM`; quota에서 제외하려면 `KEY_ALLOC_NOT_IN_QUOTA`를 쓴다.
`restrict_link`가 있으면 새 key link마다 허용 여부를 검사하는 함수와 선택적 key·type을 담는다. type 정보는 unregister 때 garbage collector가 함수·데이터 포인터를 정리하는 데 쓴다. 커널의 `key_create_or_update()` caller는 `KEY_ALLOC_BYPASS_RESTRICTION`으로 검사를 우회할 수 있다. 부팅 때 만든 암호 keyring에 사용자 공간이 기존 kernel key로 검증 가능한 key만 추가하게 하는 것이 예다. restriction 함수는 destination ring, type, 새 payload와 검사 데이터를 받아 허용 0 또는 거부 오류를 반환하며 `restrict_link_reject`는 항상 `-EPERM`이다.
`validate_key()`는 expiry와 revoke를 검사해 `EKEYEXPIRED` 또는 `EKEYREVOKED`를 반환하고 NULL·비활성 CONFIG_KEYS면 0이다. `register_key_type()`은 같은 이름이면 `EEXIST`, `unregister_key_type()`은 type을 제거한다. `key_type_keyring`과 `request_key()`로 특정 keyring을 찾고 `keyring_search()`로 내부를 검색할 수 있지만 request_key로 특정 ring 하나를 직접 검색할 수 없어 활용은 제한적이다.
새 payload를 ring에 넣기 전에 restriction callback이 검증한다.
* A keyring can be created by::
struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
const struct cred *cred,
key_perm_t perm,
struct key_restriction *restrict_link,
unsigned long flags,
struct key *dest);
This creates a keyring with the given attributes and returns it. If dest
is not NULL, the new keyring will be linked into the keyring to which it
points. No permission checks are made upon the destination keyring.
Error EDQUOT can be returned if the keyring would overload the quota (pass
KEY_ALLOC_NOT_IN_QUOTA in flags if the keyring shouldn't be accounted
towards the user's quota). Error ENOMEM can also be returned.
If restrict_link is not NULL, it should point to a structure that contains
the function that will be called each time an attempt is made to link a
key into the new keyring. The structure may also contain a key pointer
and an associated key type. The function is called to check whether a key
may be added into the keyring or not. The key type is used by the garbage
collector to clean up function or data pointers in this structure if the
given key type is unregistered. Callers of key_create_or_update() within
the kernel can pass KEY_ALLOC_BYPASS_RESTRICTION to suppress the check.
An example of using this is to manage rings of cryptographic keys that are
set up when the kernel boots where userspace is also permitted to add keys
- provided they can be verified by a key the kernel already has.
When called, the restriction function will be passed the keyring being
added to, the key type, the payload of the key being added, and data to be
used in the restriction check. Note that when a new key is being created,
this is called between payload preparsing and actual key creation. The
function should return 0 to allow the link or an error to reject it.
A convenience function, restrict_link_reject, exists to always return
-EPERM to in this case.
* To check the validity of a key, this function can be called::
int validate_key(struct key *key);
This checks that the key in question hasn't expired or and hasn't been
revoked. Should the key be invalid, error EKEYEXPIRED or EKEYREVOKED will
be returned. If the key is NULL or if CONFIG_KEYS is not set then 0 will be
returned (in the latter case without parsing the argument).
* To register a key type, the following function should be called::
int register_key_type(struct key_type *type);
This will return error EEXIST if a type of the same name is already
present.
* To unregister a key type, call::
void unregister_key_type(struct key_type *type);
Under some circumstances, it may be desirable to deal with a bundle of keys.
The facility provides access to the keyring type for managing such a bundle::
struct key_type key_type_keyring;
This can be used with a function such as request_key() to find a specific
keyring in a process's keyrings. A keyring thus found can then be searched
with keyring_search(). Note that it is not possible to use request_key() to
search a specific keyring, so using keyrings in this way is of limited utility.
Payload 동시성 접근 규칙
1328-1394payload가 `key->payload`에 직접 든 단순 값이면 RCU나 lock 없이 읽을 수 있다. 복잡한 payload는 별도 할당하고 포인터를 `key->payload.data[]`에 저장하므로 세 방법 중 하나를 택한다. modify method가 없는 type은 instantiated임을 안다면 lock 없이 접근할 수 있다. key semaphore를 쓰면 수정은 write lock, 일반 접근은 read lock이지만 accessor가 sleep해야 할 수 있다.
semaphore를 이미 보유하지 않았다면 RCU를 사용한다. 수정도 semaphore로 직렬화하므로 보유 중에는 예기치 않게 내용이 바뀌지 않는다. 읽기는 `rcu_read_lock()`·`rcu_dereference()`·`rcu_read_unlock()`, 교체는 `rcu_dereference()`·`rcu_assign_pointer()`·`call_rcu()`로 grace period 뒤 이전 payload를 버린다. payload 수정은 key type만 해야 한다.
RCU payload는 `struct rcu_head`와 가변 크기라면 자체 length를 가져야 한다. semaphore 없이 dereference한 payload와 `key->datalen`의 일관성은 보장되지 않는다. 첫 포인터의 `__rcu` shadow는 `key->payload.rcu_data0`이며 `rcu_assign_keypointer()`로 설정, semaphore 보유 중 `dereference_key_locked()`, RCU read lock 중 `dereference_key_rcu()`로 읽는다.
type의 변경 가능성과 caller context에 따라 선택한다.
Notes On Accessing Payload Contents
===================================
The simplest payload is just data stored in key->payload directly. In this
case, there's no need to indulge in RCU or locking when accessing the payload.
More complex payload contents must be allocated and pointers to them set in the
key->payload.data[] array. One of the following ways must be selected to
access the data:
1) Unmodifiable key type.
If the key type does not have a modify method, then the key's payload can
be accessed without any form of locking, provided that it's known to be
instantiated (uninstantiated keys cannot be "found").
2) The key's semaphore.
The semaphore could be used to govern access to the payload and to control
the payload pointer. It must be write-locked for modifications and would
have to be read-locked for general access. The disadvantage of doing this
is that the accessor may be required to sleep.
3) RCU.
RCU must be used when the semaphore isn't already held; if the semaphore
is held then the contents can't change under you unexpectedly as the
semaphore must still be used to serialise modifications to the key. The
key management code takes care of this for the key type.
However, this means using::
rcu_read_lock() ... rcu_dereference() ... rcu_read_unlock()
to read the pointer, and::
rcu_dereference() ... rcu_assign_pointer() ... call_rcu()
to set the pointer and dispose of the old contents after a grace period.
Note that only the key type should ever modify a key's payload.
Furthermore, an RCU controlled payload must hold a struct rcu_head for the
use of call_rcu() and, if the payload is of variable size, the length of
the payload. key->datalen cannot be relied upon to be consistent with the
payload just dereferenced if the key's semaphore is not held.
Note that key->payload.data[0] has a shadow that is marked for __rcu
usage. This is called key->payload.rcu_data0. The following accessors
wrap the RCU calls to this element:
a) Set or change the first payload pointer::
rcu_assign_keypointer(struct key *key, void *data);
b) Read the first payload pointer with the key semaphore held::
[const] void *dereference_key_locked([const] struct key *key);
Note that the return value will inherit its constness from the key
parameter. Static analysis will give an error if it things the lock
isn't held.
c) Read the first payload pointer with the RCU read lock held::
const void *dereference_key_rcu(const struct key *key);
key_type의 이름·quota·description 검증
1395-1435파일 시스템 등 커널 서비스는 `<linux/key-type.h>`를 포함하고 `struct key_type`을 채워 등록해 자체 type을 정의한다. 예를 들어 AFS는 Kerberos 5 ticket type을 만들 수 있다. 필수 `name`은 사용자 공간 type 문자열을 구조체 포인터로 변환할 때 쓴다.
선택적 `def_datalen`은 payload가 거의 고정 크기일 때 quota에 기본 반영할 길이다. 특정 key의 길이와 quota는 `key_payload_reserve(key, datalen)`로 바꾸며 불가능하면 `EDQUOT`다. 선택적 `vet_description()`은 description을 승인하면 0, 거부하면 오류를 반환한다.
Defining a Key Type
===================
A kernel service may want to define its own key type. For instance, an AFS
filesystem might want to define a Kerberos 5 ticket key type. To do this, it
author fills in a key_type struct and registers it with the system.
Source files that implement key types should include the following header file::
<linux/key-type.h>
The structure has a number of fields, some of which are mandatory:
* ``const char *name``
The name of the key type. This is used to translate a key type name
supplied by userspace into a pointer to the structure.
* ``size_t def_datalen``
This is optional - it supplies the default payload data length as
contributed to the quota. If the key type's payload is always or almost
always the same size, then this is a more efficient way to do things.
The data length (and quota) on a particular key can always be changed
during instantiation or update by calling::
int key_payload_reserve(struct key *key, size_t datalen);
With the revised data length. Error EDQUOT will be returned if this is not
viable.
* ``int (*vet_description)(const char *description);``
This optional method is called to vet a key description. If the key type
doesn't approve of the key description, it may return an error, otherwise
it should return 0.
preparse·free_preparse·instantiate
1436-1500선택적 `preparse(prep)`는 add에서는 key 생성 전, update·instantiate에서는 semaphore 획득 전에 payload를 parse한다. `key_preparsed_payload`에는 description, union payload, 원본 data·datalen, quota 길이, expiry가 있다. 호출 전 data·datalen은 입력 blob, quotalen은 type 기본값, expiry는 `TIME_T_MAX`, 나머지는 0이다. payload에서 description을 만들 수 있으면 문자열을 붙여 `add_key()`가 NULL 또는 빈 description을 줬을 때 사용한다. parse한 자료는 payload에 붙여 instantiate/update로 전달하고 expiry도 적용하며 성공 0 또는 음수 오류를 반환한다.
`free_preparse()`는 preparse가 있을 때 필요하며 성공한 preparse 뒤 instantiate/update 성공 여부와 무관하게 항상 호출되어 description·payload의 임시 자원을 정리한다.
`instantiate(key, prep)`는 construction 중 payload를 붙인다. 원본 blob과 다른 내부 표현도 가능하고 실제 길이가 `def_datalen`과 다르면 `key_payload_reserve()`를 호출한다. `KEY_FLAG_INSTANTIATED`가 아직 없어 외부 접근이 차단되므로 별도 key lock 없이 붙일 수 있고 sleep 가능하다. `generic_key_instantiate()`는 prep payload 배열을 key payload로 복사하며 첫 원소는 RCU-safe하게 지정하고 prep 배열을 지워 free_preparse가 데이터를 해제하지 않게 한다.
parse 임시 자료는 instantiate 뒤 반드시 정리된다.
* ``int (*preparse)(struct key_preparsed_payload *prep);``
This optional method permits the key type to attempt to parse payload
before a key is created (add key) or the key semaphore is taken (update or
instantiate key). The structure pointed to by prep looks like::
struct key_preparsed_payload {
char *description;
union key_payload payload;
const void *data;
size_t datalen;
size_t quotalen;
time_t expiry;
};
Before calling the method, the caller will fill in data and datalen with
the payload blob parameters; quotalen will be filled in with the default
quota size from the key type; expiry will be set to TIME_T_MAX and the
rest will be cleared.
If a description can be proposed from the payload contents, that should be
attached as a string to the description field. This will be used for the
key description if the caller of add_key() passes NULL or "".
The method can attach anything it likes to payload. This is merely passed
along to the instantiate() or update() operations. If set, the expiry
time will be applied to the key if it is instantiated from this data.
The method should return 0 if successful or a negative error code
otherwise.
* ``void (*free_preparse)(struct key_preparsed_payload *prep);``
This method is only required if the preparse() method is provided,
otherwise it is unused. It cleans up anything attached to the description
and payload fields of the key_preparsed_payload struct as filled in by the
preparse() method. It will always be called after preparse() returns
successfully, even if instantiate() or update() succeed.
* ``int (*instantiate)(struct key *key, struct key_preparsed_payload *prep);``
This method is called to attach a payload to a key during construction.
The payload attached need not bear any relation to the data passed to this
function.
The prep->data and prep->datalen fields will define the original payload
blob. If preparse() was supplied then other fields may be filled in also.
If the amount of data attached to the key differs from the size in
keytype->def_datalen, then key_payload_reserve() should be called.
This method does not have to lock the key in order to attach a payload.
The fact that KEY_FLAG_INSTANTIATED is not set in key->flags prevents
anything else from gaining access to the key.
It is safe to sleep in this method.
generic_key_instantiate() is provided to simply copy the data from
prep->payload.data[] to key->payload.data[], with RCU-safe assignment on
the first element. It will then clear prep->payload.data[] so that the
free_preparse method doesn't release the data.
update callback의 실패 경계와 RCU
1501-1525type이 update 가능하면 `update()`를 제공해 입력 blob으로 payload를 바꾼다. 길이가 달라질 수 있으면 실제 변경 전에 `key_payload_reserve()`를 호출해야 한다. reserve 성공은 quota가 이미 바뀌어 type이 key 변경을 완료해야 한다는 뜻이므로 모든 메모리 할당과 실패 가능한 호출을 먼저 끝낸 뒤 reserve하고 변경한다.
호출 전 key semaphore는 write-lock 상태지만 이는 다른 writer만 막는다. reader와 안전하게 payload를 바꾸려면 RCU 조건에서 교체하고 `call_rcu()`로 이전 payload를 폐기한다. 이 method는 sleep 가능하다.
* ``int (*update)(struct key *key, const void *data, size_t datalen);``
If this type of key can be updated, then this method should be provided.
It is called to update a key's payload from the blob of data provided.
The prep->data and prep->datalen fields will define the original payload
blob. If preparse() was supplied then other fields may be filled in also.
key_payload_reserve() should be called if the data length might change
before any changes are actually made. Note that if this succeeds, the type
is committed to changing the key because it's already been altered, so all
memory allocation must be done first.
The key will have its semaphore write-locked before this method is called,
but this only deters other writers; any changes to the key's payload must
be made under RCU conditions, and call_rcu() must be used to dispose of
the old payload.
key_payload_reserve() should be called before the changes are made, but
after all allocations and other potentially failing function calls are
made.
It is safe to sleep in this method.
검색 preparse와 비교 함수
1526-1576선택적 `match_preparse(match_data)`는 검색 직전에 호출된다. `raw_data`는 caller 검색 기준으로 수정하면 안 된다. 기본 `cmp`는 description과 정확히 비교하고 `lookup_type`은 direct다. `KEYRING_SEARCH_LOOKUP_DIRECT`는 type·description hash로 후보를 줄이고, `ITERATE`는 ring의 모든 key를 순회하므로 단순 description match가 아닌 검색은 ITERATE를 써야 한다.
method는 자체 `cmp`, ITERATE lookup, 비교용 `preparsed` 자료를 설정할 수 있다. cmp는 일치 true, 불일치 false이며 lock 아래 호출되어 sleep할 수 없다. match_preparse 자체는 sleep 가능하고 성공 0 또는 음수 오류를 반환한다. 임시 자료는 선택적 `match_free()`가 정리한다. match_preparse가 없으면 description exact match다.
description exact match 여부에 따라 lookup 전략이 달라진다.
* ``int (*match_preparse)(struct key_match_data *match_data);``
This method is optional. It is called when a key search is about to be
performed. It is given the following structure::
struct key_match_data {
bool (*cmp)(const struct key *key,
const struct key_match_data *match_data);
const void *raw_data;
void *preparsed;
unsigned lookup_type;
};
On entry, raw_data will be pointing to the criteria to be used in matching
a key by the caller and should not be modified. ``(*cmp)()`` will be pointing
to the default matcher function (which does an exact description match
against raw_data) and lookup_type will be set to indicate a direct lookup.
The following lookup_type values are available:
* KEYRING_SEARCH_LOOKUP_DIRECT - A direct lookup hashes the type and
description to narrow down the search to a small number of keys.
* KEYRING_SEARCH_LOOKUP_ITERATE - An iterative lookup walks all the
keys in the keyring until one is matched. This must be used for any
search that's not doing a simple direct match on the key description.
The method may set cmp to point to a function of its choice that does some
other form of match, may set lookup_type to KEYRING_SEARCH_LOOKUP_ITERATE
and may attach something to the preparsed pointer for use by ``(*cmp)()``.
``(*cmp)()`` should return true if a key matches and false otherwise.
If preparsed is set, it may be necessary to use the match_free() method to
clean it up.
The method should return 0 if successful or a negative error code
otherwise.
It is permitted to sleep in this method, but ``(*cmp)()`` may not sleep as
locks will be held over it.
If match_preparse() is not provided, keys of this type will be matched
exactly by their description.
* ``void (*match_free)(struct key_match_data *match_data);``
This method is optional. If given, it called to clean up
match_data->preparsed after a successful call to match_preparse().
revoke·destroy·describe·read callback
1577-1630선택적 `revoke()`는 revoke 때 payload 일부를 버리며 caller가 key semaphore를 write-lock한다. sleep 가능하지만 semaphore deadlock을 피해야 한다. `destroy()`는 key 파괴 때 payload를 버리고 더 이상 접근할 수 없으므로 lock이 필요 없지만 caller가 spinlock을 보유할 수 있어 sleep하면 안 된다. 호출 전에 key type이 바뀌었을 수도 있다.
`describe()`는 `/proc/keys`용 텍스트 요약을 만든다. RCU read lock 아래 호출되므로 payload 포인터는 `rcu_dereference()`로 읽고 `key->datalen` 일관성을 믿으면 안 된다. description은 불변이지만 상태는 바뀔 수 있고 sleep 금지다.
`read()`는 `KEYCTL_READ`에 내부 payload를 사용자 공간 blob으로 변환하며 가능하면 instantiate/update 입력 형식과 같게 한다. 복사량이 아니라 만들 수 있는 전체 blob 크기를 반환해야 한다. key semaphore read-lock 아래라 payload가 바뀌지 않으므로 RCU lock은 불필요하고 사용자 buffer 접근 중 sleep할 수 있다.
각 callback의 lock과 sleep 조건이다.
* ``void (*revoke)(struct key *key);``
This method is optional. It is called to discard part of the payload
data upon a key being revoked. The caller will have the key semaphore
write-locked.
It is safe to sleep in this method, though care should be taken to avoid
a deadlock against the key semaphore.
* ``void (*destroy)(struct key *key);``
This method is optional. It is called to discard the payload data on a key
when it is being destroyed.
This method does not need to lock the key to access the payload; it can
consider the key as being inaccessible at this time. Note that the key's
type may have been changed before this function is called.
It is not safe to sleep in this method; the caller may hold spinlocks.
* ``void (*describe)(const struct key *key, struct seq_file *p);``
This method is optional. It is called during /proc/keys reading to
summarise a key's description and payload in text form.
This method will be called with the RCU read lock held. rcu_dereference()
should be used to read the payload pointer if the payload is to be
accessed. key->datalen cannot be trusted to stay consistent with the
contents of the payload.
The description will not change, though the key's state may.
It is not safe to sleep in this method; the RCU read lock is held by the
caller.
* ``long (*read)(const struct key *key, char __user *buffer, size_t buflen);``
This method is optional. It is called by KEYCTL_READ to translate the
key's payload into something a blob of data for userspace to deal with.
Ideally, the blob should be in the same format as that passed in to the
instantiate and update methods.
If successful, the blob size that could be produced should be returned
rather than the size copied.
This method will be called with the key's semaphore read-locked. This will
prevent the key's payload changing. It is not necessary to use RCU locking
when accessing the key's payload. It is safe to sleep in this method, such
as might happen when the userspace buffer is accessed.
type별 request_key와 restriction parser
1631-1678선택적 `key_type->request_key(cons, op, aux)`가 있으면 `request_key()` 계열은 `/sbin/request-key` 대신 이 callback을 호출한다. aux는 auxdata 요청에서 전달한 값, op는 현재 `create`, cons는 construction record다. 비동기로 먼저 반환할 수 있지만 성공·실패·오류 여부와 무관하게 반드시 `complete_request_key(cons, error)`를 호출해야 한다.
complete의 error는 성공 0, 실패 음수다. 호출하면 construction record를 파괴하고 authorization key를 revoke하며, 오류 시 아직 완성되지 않은 key를 negative instantiate한다. callback이 오류를 직접 반환할 때도 반환 전 complete를 호출해야 한다. cons에는 construction 중 `key`와 `authkey`가 있다.
선택적 `lookup_restriction(params)`는 사용자 공간이 keyring restriction을 설정하게 한다. type 이름을 뺀 parameter 문자열을 해석해 link 시도마다 평가할 함수·데이터가 든 `key_restriction`을 반환하고 일치 방식이 없으면 `-EINVAL`이다.
어떤 종료 경로에서도 construction을 명시적으로 완료한다.
* ``int (*request_key)(struct key_construction *cons, const char *op, void *aux);``
This method is optional. If provided, request_key() and friends will
invoke this function rather than upcalling to /sbin/request-key to operate
upon a key of this type.
The aux parameter is as passed to request_key_async_with_auxdata() and
similar or is NULL otherwise. Also passed are the construction record for
the key to be operated upon and the operation type (currently only
"create").
This method is permitted to return before the upcall is complete, but the
following function must be called under all circumstances to complete the
instantiation process, whether or not it succeeds, whether or not there's
an error::
void complete_request_key(struct key_construction *cons, int error);
The error parameter should be 0 on success, -ve on error. The
construction record is destroyed by this action and the authorisation key
will be revoked. If an error is indicated, the key under construction
will be negatively instantiated if it wasn't already instantiated.
If this method returns an error, that error will be returned to the
caller of request_key*(). complete_request_key() must be called prior to
returning.
The key under construction and the authorisation key can be found in the
key_construction struct pointed to by cons:
* ``struct key *key;``
The key under construction.
* ``struct key *authkey;``
The authorisation key.
* ``struct key_restriction *(*lookup_restriction)(const char *params);``
This optional method is used to enable userspace configuration of keyring
restrictions. The restriction parameter string (not including the key type
name) is passed in, and this method returns a pointer to a key_restriction
structure containing the relevant functions and data to evaluate each
attempted key link operation. If there is no match, -EINVAL is returned.
asym_eds_op와 signature verification
1679-1748선택적 `asym_eds_op()`는 encrypt·decrypt·sign, `asym_verify_signature()`는 signature verify를 수행한다. `kernel_pkey_params`에는 사용할 key, encoding(`pkcs1` 또는 `raw` 등), signature data를 만든 hash algorithm, 보조 info, input과 output 또는 second input 길이, operation ID가 있다.
operation별 buffer는 사용자 공간 PKEY와 같다. encrypt와 sign은 raw input을 encrypted result 또는 signature output으로 만들며 encoding이 있으면 padding을 추가하고 sign padding이 digest algorithm을 표시해야 하면 `hash_algo`를 사용한다. decrypt는 encrypted input을 raw output으로 만들며 padding을 검사·제거한다. verify는 raw input과 second input의 signature를 비교하고 padding과 필요한 hash algorithm을 검증한다.
성공 시 `asym_eds_op()`는 output byte 수, verify는 0을 반환한다. 미지원은 `EOPNOTSUPP`, 검증 실패는 `EKEYREJECTED`, 필요한 crypto package가 없으면 `ENOPKG` 등 오류를 반환할 수 있다.
* ``asym_eds_op`` and ``asym_verify_signature``::
int (*asym_eds_op)(struct kernel_pkey_params *params,
const void *in, void *out);
int (*asym_verify_signature)(struct kernel_pkey_params *params,
const void *in, const void *in2);
These methods are optional. If provided the first allows a key to be
used to encrypt, decrypt or sign a blob of data, and the second allows a
key to verify a signature.
In all cases, the following information is provided in the params block::
struct kernel_pkey_params {
struct key *key;
const char *encoding;
const char *hash_algo;
char *info;
__u32 in_len;
union {
__u32 out_len;
__u32 in2_len;
};
enum kernel_pkey_operation op : 8;
};
This includes the key to be used; a string indicating the encoding to use
(for instance, "pkcs1" may be used with an RSA key to indicate
RSASSA-PKCS1-v1.5 or RSAES-PKCS1-v1.5 encoding or "raw" if no encoding);
the name of the hash algorithm used to generate the data for a signature
(if appropriate); the sizes of the input and output (or second input)
buffers; and the ID of the operation to be performed.
For a given operation ID, the input and output buffers are used as
follows::
Operation ID in,in_len out,out_len in2,in2_len
======================= =============== =============== ===============
kernel_pkey_encrypt Raw data Encrypted data -
kernel_pkey_decrypt Encrypted data Raw data -
kernel_pkey_sign Raw data Signature -
kernel_pkey_verify Raw data - Signature
asym_eds_op() deals with encryption, decryption and signature creation as
specified by params->op. Note that params->op is also set for
asym_verify_signature().
Encrypting and signature creation both take raw data in the input buffer
and return the encrypted result in the output buffer. Padding may have
been added if an encoding was set. In the case of signature creation,
depending on the encoding, the padding created may need to indicate the
digest algorithm - the name of which should be supplied in hash_algo.
Decryption takes encrypted data in the input buffer and returns the raw
data in the output buffer. Padding will get checked and stripped off if
an encoding was set.
Verification takes raw data in the input buffer and the signature in the
second input buffer and checks that the one matches the other. Padding
will be validated. Depending on the encoding, the digest algorithm used
to generate the raw data may need to be indicated in hash_algo.
If successful, asym_eds_op() should return the number of bytes written
into the output buffer. asym_verify_signature() should return 0.
A variety of errors may be returned, including EOPNOTSUPP if the operation
is not supported; EKEYREJECTED if verification fails; ENOPKG if the
required crypto isn't available.
asym_query 결과
1749-1788선택적 `asym_query(params, info)`는 key가 가진 public 또는 asymmetric key 정보를 알아낸다. parameter는 암호 연산과 같지만 input/output 길이는 쓰지 않고 encoding·hash algorithm으로 적절한 buffer/data 최대 크기를 좁힌다.
성공 결과 `kernel_pkey_query`는 supported operation bitmask, bit 단위 key size, signature 생성·검증의 raw data와 signature 최대 크기, encrypt·decrypt의 최대 크기를 byte 단위로 제공한다. 지원 bit는 `KEYCTL_SUPPORTS_{ENCRYPT,DECRYPT,SIGN,VERIFY}`다. 성공 0, 미지원은 `EOPNOTSUPP`다.
* ``asym_query``::
int (*asym_query)(const struct kernel_pkey_params *params,
struct kernel_pkey_query *info);
This method is optional. If provided it allows information about the
public or asymmetric key held in the key to be determined.
The parameter block is as for asym_eds_op() and co. but in_len and out_len
are unused. The encoding and hash_algo fields should be used to reduce
the returned buffer/data sizes as appropriate.
If successful, the following information is filled in::
struct kernel_pkey_query {
__u32 supported_ops;
__u32 key_size;
__u16 max_data_size;
__u16 max_sig_size;
__u16 max_enc_size;
__u16 max_dec_size;
};
The supported_ops field will contain a bitmask indicating what operations
are supported by the key, including encryption of a blob, decryption of a
blob, signing a blob and verifying the signature on a blob. The following
constants are defined for this::
KEYCTL_SUPPORTS_{ENCRYPT,DECRYPT,SIGN,VERIFY}
The key_size field is the size of the key in bits. max_data_size and
max_sig_size are the maximum raw data and signature sizes for creation and
verification of a signature; max_enc_size and max_dec_size are the maximum
raw data and signature sizes for encryption and decryption. The
max_*_size fields are measured in bytes.
If successful, 0 will be returned. If the key doesn't support this,
EOPNOTSUPP will be returned.
/sbin/request-key callback protocol
1789-1838새 key가 필요하면 커널은 `/sbin/request-key create <key> <uid> <gid> <threadring> <processring> <sessionring> <callout_info>`를 실행한다. 세 ring은 요청을 일으킨 프로세스의 keyring이며 필요한 Kerberos TGT 같은 인증 token을 찾고 새 key를 cache할 위치를 제공한다.
프로그램은 추가 key에 접근하기 전에 지정 UID·GID로 전환하고, KDE desktop manager가 다른 key에 둔 경로처럼 사용자별 프로세스에 요청을 넘길 수 있다. 완료하려면 `KEYCTL_INSTANTIATE` 또는 IOV 버전으로 key를 만들고 보통 session ring에 cache한다. 실패는 `KEYCTL_NEGATE` 또는 `REJECT`로 표시·cache한다. unconstructed 상태로 반환하면 자동 negative, session keyring link, requester 오류가 발생한다. 추가 정보가 없으면 callout_info에 `-`가 전달된다.
expired 또는 곧 만료될 key update에는 `/sbin/request-key update <key> <uid> <gid> <threadring> <processring> <sessionring>`을 실행한다. 이 경우 ring은 참고용이며 실제 link는 요구되지 않는다.
커널 요청은 사용자 공간 helper가 positive 또는 negative로 반드시 종결한다.
Request-Key Callback Service
============================
To create a new key, the kernel will attempt to execute the following command
line::
/sbin/request-key create <key> <uid> <gid> \
<threadring> <processring> <sessionring> <callout_info>
<key> is the key being constructed, and the three keyrings are the process
keyrings from the process that caused the search to be issued. These are
included for two reasons:
1 There may be an authentication token in one of the keyrings that is
required to obtain the key, eg: a Kerberos Ticket-Granting Ticket.
2 The new key should probably be cached in one of these rings.
This program should set it UID and GID to those specified before attempting to
access any more keys. It may then look around for a user specific process to
hand the request off to (perhaps a path held in placed in another key by, for
example, the KDE desktop manager).
The program (or whatever it calls) should finish construction of the key by
calling KEYCTL_INSTANTIATE or KEYCTL_INSTANTIATE_IOV, which also permits it to
cache the key in one of the keyrings (probably the session ring) before
returning. Alternatively, the key can be marked as negative with KEYCTL_NEGATE
or KEYCTL_REJECT; this also permits the key to be cached in one of the
keyrings.
If it returns with the key remaining in the unconstructed state, the key will
be marked as being negative, it will be added to the session keyring, and an
error will be returned to the key requestor.
Supplementary information may be provided from whoever or whatever invoked this
service. This will be passed as the <callout_info> parameter. If no such
information was made available, then "-" will be passed as this parameter
instead.
Similarly, the kernel may attempt to update an expired or a soon to expire key
by executing::
/sbin/request-key update <key> <uid> <gid> \
<threadring> <processring> <sessionring>
In this case, the program isn't required to actually attach the key to a ring;
the rings are provided for reference.
Dead·Revoked·Expired key 수거
1839-1849type이 제거된 dead key는 background garbage collector가 자신을 가리키는 모든 keyring에서 자동 unlink하고 가능한 빨리 삭제한다. revoked와 expired key도 수거하지만 일정 지연 뒤 처리하며 지연 초는 `/proc/sys/kernel/keys/gc_delay`에 설정한다.
상태별 수거 시점이다.
Garbage Collection
==================
Dead keys (for which the type has been removed) will be automatically unlinked
from those keyrings that point to them and deleted as soon as possible by a
background garbage collector.
Similarly, revoked and expired keys will be garbage collected, but only after a
certain amount of time has passed. This time is set as a number of seconds in::
/proc/sys/kernel/keys/gc_delay
요약·해설
core.rst:1-1849커널 키 보존 서비스의 데이터 모델과 권한, 표준 keyring 수명, 모든 주요 KEYCTL 명령, 커널 참조 관리와 RCU payload 규칙, key_type callback별 lock·sleep 계약, request-key upcall과 garbage collection을 하나의 수명 주기로 연결해 설명합니다.