The Linux key retention service, introduced with the Linux 2.6 kernel, is primarily intended to cache authentication data in the Linux kernel. The service can be used by remote filesystems or other kernel services to manage cryptography, authentication tokens, cross-domain user mappings, and other security concerns. It also enables the Linux kernel to access required keys rapidly, and can be used to delegate key operations such as add, update, and delete to user-space.
This article gives you an overview of the Linux key retention service, defines its terminology, and helps you get started quickly with using Linux keys. You see how to use the Linux key retention service in a kernel module using sample code. The kernel version used in writing this article is 2.6.20.
A key is a unit of cryptographic data, an authentication token, or some
similar element represented in the kernel by
struct key. struct key is
defined in the Linux kernel source under
include/linux/key.h.
Listing 1 shows some important fields from struct key.
Note that task_struct,
user_struct, and
signal_struct have been modified to add support for
keys.
Listing 1. Important fields from struct key
struct key {
atomic_t usage; /* number of references */
key_serial_t serial; /* key serial number */
struct key_type *type; /* type of key */
time_t expiry; /* time at which key expires (or 0) */
uid_t uid; /* UID */
gid_t gid; /* GID */
key_perm_t perm; /* access permissions */
unsigned short quotalen; /* length added to quota */
unsigned short datalen; /* payload data length
char *description;
union {
unsigned long value;
void *data;
struct keyring_list *subscriptions;
} payload; /* Actual security data */
....
....
};
|
A key has the following attributes:
- Serial number: A unique 32-bit non-zero positive number.
- Type: The Linux key retention service defines two standard key types:
user and keyring. To add a new key type, it must be registered by a kernel
service. User-space programs are not allowed to create new key types. Key types
are represented in the kernel by
struct key_type, which is defined ininclude/linux/key.h. Some important fields of thekey_typestructure are shown in Listing 2.
Listing 2. Important fields of key_typestruct key_type { const char *name; size_t def_datalen; /* Operations that can be defined for a key_type */ int (*instantiate)(struct key *key, const void *data, size_t datalen); int (*update)(struct key *key, const void *data, size_t datalen); int (*match)(const struct key *key, const void *desc); void (*revoke)(struct key *key); void (*destroy)(struct key *key); void (*describe)(const struct key *key, struct seq_file *p); long (*read)(const struct key *key, char __user *buffer, size_t buflen); .... .... };
You can also associate a set of operations to a key type. Akey_typecan define the following operations:instantiatecreates a new key of a specified type.describeprints text describing the key.matchsearches a key based on its description.destroyclears all data related to a key.request_keysearches for a key.revokeclears key data and changes the state of the key toREVOKED.readreads key data.updatemodifies a key.
- Description: A printable string that describes the key. This attribute can also be used to perform search operations.
- Access control information: Each key has an owner UID, a GID, and a
permissions mask that dictates how it will respond to user-level or kernel-level
programs. The permissions mask allocates 8 bits each to the four possible types
of key accessor: possessor, user, group, and other. Out of the 8 bits, only 6
bits are defined. The possible permissions are as follows:
Viewallows the possessor to view key attributes.Readallows the possessor to read the key and lists the key for a keyring.Writeallows the possessor to modify the payload for a key or keyring and to modify linked keys.Searchallows the possessor to search keyrings and find keys.Linkallows the possessor to link a particular key or keyring to a keyring.Set Attributeallows the possessor to set the key's UID, GID, and permissions mask.
- Expiry Time: Lifetime of a key. Keys can also be permanent.
- Payload: The actual security data. Operations defined with
struct key_typeare used to instantiate the payload with data and also to read back or modify the data. To the kernel, the payload is just a blob of data. - State: A key can be in any of the following states:
UNINSTANTIATED: The key has been created but is not yet attached to any data.INSTANTIATED: The key is instantiated and attached to data; this is a complete state.NEGATIVE: A temporary state that denotes that the previous call to user-space failed.EXPIRED: Indicates the key has outgrown its pre-defined lifetime.REVOKED: The key is moved to this state by a user-space action.DEAD: Thekey_typeis unregistered.
There are two defined key types: keyring and user.
A keyring is a key that contain a set of links to other keys or keyrings. There are six standard keyrings:
- Thread-specific
- Process-specific
- Session-specific
- User-specific session
- User-default session
- Group-specific (not yet implemented)
Only the first three keyrings are automatically searched, in which case they are searched in order. The fourth type, a user-specific session keyring, is not searched directly but it is normally linked to from a session-specific keyring. Login processes such as PAM will bind to the user-default session keyring until another session is created.
User keys are defined to be manipulated by user-space programs.
The Linux key retention service provides three new syscalls to manipulate keys in user-space. The first is add_key:
key_serial_t add_key(const char *type, const char *desc,
const void *payload, size_t plen,
key_serial_t ring);
|
The add_key syscall is used to create keys of type
type and length plen. The
key description is defined by desc, and its payload is
pointed to by payload. The key is linked to the keyring
ring. The key type can be user or
keyring. Any other key type must be already registered with the kernel via
a kernel service. If the key is of type keyring, the payload should be
NULL and the plen should be
zero.
The next new syscall is request_key:
key_serial_t request_key(const char *type, const char *desc,
const char *callout_info,
key_serial_t dest_keyring);
|
The request_key syscall searches a process keyring for
a key. The basic algorithm used to search for a key is shown in Listing 3.
Listing 3. The request_key algorithm
search_into_each_subscribed_keyrings {
if(key is found){
return(found key);
} else {
if(callout_info is NULL){
return(ERROR);
} else {
Execute /sbin/request-key and pass callout_info as argument;
}
}
}
|
For detailed information on the workings of the
request_key algorithm, refer to
Documentation/keys-request-key.txt (see Resources for a
link).
Finally, the syscall keyctl provides a number of functions for managing
keys. Various operation can be performed on keys depending on the first argument
passed to keyctl. Some of
keyctl's operations are listed below:
KEYCTL_DESCRIBEdescribes a key.KEYCTL_READreads payload data from a key.KEYCTL_UPDATEupdates the specified key.KEYCTL_LINKlinks a key into a keyring.KEYCTL_UNLINKunlinks a key or keyring from another keyring.KEYCTL_JOIN_SESSION_KEYRINGreplaces a session keyring with a new one.KEYCTL_REVOKErevokes a key.KEYCTL_CHOWNchanges the ownership of a key.KEYCTL_SETPERMchanges the permissions mask on a key.KEYCTL_CLEARclears out a keyring.KEYCTL_SEARCHsearches a keyring tree for a key.KEYCTL_INSTANTIATEinstantiates a partially constructed key.KEYCTL_NEGATEnegatively instantiates a partially constructed key.
For more information on the prototype of keyctl or
other possible operations that can be performed by
keyctl, refer to the Linux man pages.
Below is a short listing of the most important Linux kernel APIs for managing keys. For more comprehensive information, download and refer to the Linux key implementation source files (see Download, below).
- register_key_type is used to define a new key type.
- int register_key_type(struct key_type *type) returns
EEXITif a key type of the same name already exists. - unregister_key_type is used to unregister a key type:
void unregister_key_type(struct key_type *type);
- key_put releases a key:
void key_put(struct key *key);
- request_key searches for a key matching a given description:
struct key *request_key(const struct key_type *type, const char *description, const char *callout_string); - key_alloc allocates a key of a specified type:
struct key *key_alloc(struct key_type *type, const char *desc, uid_t uid, gid_t gid, struct task_struct *ctx, key_perm_t perm, unsigned long flags); - key_instantiate_and_link instantiates a key and links it into the
target keyring atomically:
int key_instantiate_and_link(struct key *key, const void *data, size_t datalen, struct key *keyring, struct key *instkey);
Because the Linux key retention service is still very new, it is turned off by
default in the Linux kernel. To enable key services, you must configure the kernel
using the CONFIG_KEYS=y option. You can find this
option under Security options in the
make *config step of kernel compilation.
Listing 4 shows the configuration to enable key services in the Linux kernel.
Listing 4. Enabling key services in the kernel
".config" file ... # # Security options # CONFIG_KEYS=y CONFIG_KEYS_DEBUG_PROC_KEYS=y CONFIG_SECURITY=y CONFIG_SECURITY_NETWORK=y CONFIG_SECURITY_CAPABILITIES=y |
The source code for keys is organized in the directory linux-2.6.x/security/keys.
Next, you need to
download and install the keyutils package.
keyutils contains the keyctl
command, which you can use to perform a variety of operations on keys. We've
already listed some of keyctl's operations. See the Linux
man pages to learn more about usage.
The easiest way to learn about the Linux key retention service is to try it out.
The following examples use the Linux key retention service to create a key of a
new type. If you haven't already, go ahead and
download the sample program now. Do a
make to build the binaries of the kernel module and
user-level programs. The code has been tested with Linux kernel version 2.6.20.
The sample program has two components: a kernel module and a user-space program.
The kernel module registers a new key type. When executed, the user-space program
does an ioctl on pre-defined
proc-entries, which results in a call to the kernel
module. A new key is created as a result of this call. A "bash" shell is then
returned to the user with the new session keyring and the key of a new type linked
to the keyring.
Because the user-space program will do an ioctl, the
function proc_ioctl() must be registered by the kernel
module to handle ioctl requests. All
ioctl communication is done using the
/proc interface. Listing 5 shows a new key type being
declared in the kernel module.
Listing 5. Declaring a new key type
struct key_type new_key_type = {
.name = "mykey",
.instantiate = instantiate_key,
.describe = key_desc,
.destroy = key_destroy,
.match = key_match,
};
|
The module then calls register_key_type(), in its
init function, to register the new key, which is named
mykey. When the kernel module receives an
ioctl request, it first, creates a session keyring, by
calling key_alloc() to allocate a new key. After a
successful call to key_alloc(), we call
key_instantiate_and_link() to instantiate the key.
After we have created and instantiated the session keyring, we create the key for
the user's session. We make the same set of calls to
key_alloc(), followed by
key_instantiate_and_link(). Upon successful completion
of these calls, the user-space session has a new key.
All of these steps are demonstrated in the sample program.
Having created a new key type, we next want to try using the kernel module. A
basic operation in the module is to view what keyrings a process is subscribed to
and what keys and other keyrings those keyrings contain. A call to
keyctl show shows the keys in a tree-like structure.
Listing 6 shows the state of the keys before running our program.
Listing 6. Viewing process keyrings
[root@phoenix set.5]# keyctl show
Session Keyring
-3 --alswrv 0 0 keyring: _ses.1976
2 --alswrv 0 0 \_ keyring: _uid.0
|
Listing 7 shows the output of commands for inserting the module, or unloading the module or the user-level program. These messages go in a syslog file (typically /var/log/messages).
Listing 7. Inserting the kernel module
[root@phoenix set.5]# insmod ./kernel.land/newkey.ko Loading the module ... Registered "learning_key" |
Next, we execute the user-level program.
Listing 8. Executing the user-level program
[root@phoenix set.5]# ./user.land/session In /var/log/message, you will see similar output Installing session keyring: keyring allocated successfully. keyring instantiated and linked successfully. New session keyring installed successfully. key of new type allocated successfully. New key type linked to current session. |
And in Listing 9 we actually see the keys.
Listing 9. Status of keys after running the user-level program
[root@phoenix set.5]# keyctl show
Session Keyring
-3 --alswrv 0 0 keyring: session.2621
39044642 --alswrv 0 0 \_ mykey: New key type
[root@phoenix set.5]# cat /proc/keys
00000001 I----- 1 perm 1f3f0000 0 0 keyring _uid_ses.0: 1/4
00000002 I----- 5 perm 1f3f0000 0 0 keyring _uid.0: empty
0253c622 I--Q-- 1 perm 3f3f0000 0 0 mykey New key type: 0
11a490da I--Q-- 2 perm 3f3f0000 0 0 keyring session.2621: 1/4
13670439 I--Q-- 2 perm 1f3f0000 0 0 keyring _ses.1977: 1/4
159d39b8 I--Q-- 5 perm 1f3f0000 0 0 keyring _ses.1976: 1/4
3a14f259 I--Q-- 3 perm 1f3f0000 0 0 keyring _ses.1978: 1/4
[root@phoenix set.5]# cat /proc/key-users
0: 8 7/7 5/100 136/10000
43: 2 2/2 2/100 56/10000
48: 2 2/2 2/100 56/10000
81: 2 2/2 2/100 56/10000
786: 4 4/4 4/100 113/10000
"keyctl describe <Key>" command gives the description of key.
[root@phoenix set.5]# keyctl describe -3
-3: alswrvalswrv------------ 0 0 keyring: session.2621
[root@phoenix set.5]# keyctl describe 39044642
39044642: alswrvalswrv------------ 0 0 mykey: New key type
[avinesh@phoenix set.5]$ keyctl search -3 mykey "New key type"
39044642
[root@phoenix set.5]# exit
exit
Now back to our previous state
[root@phoenix set.5]# keyctl show
Session Keyring
-3 --alswrv 0 0 keyring: _ses.1976
2 --alswrv 0 0 \_ keyring: _uid.0
[root@phoenix set.5]# rmmod ./kernel.land/newkey.ko
Unloading the module.
Unregistered "learning_key"
|
Two files are added to /proc to monitor keys:
/proc/keys and /proc/key-users. Let's take a closer look at these files.
/proc/keys
If a process wants to know which keys it can view,
it can get that information by reading /proc/keys. This file must be enabled when
the kernel is configured, because it allows any user to list the keys database.
Listing 10. The /proc/keys file
[root@phoenix set.5]# cat /proc/keys 00000001 I----- 1 perm 1f3f0000 0 0 keyring _uid_ses.0 : 1/4 00000002 I----- 5 perm 1f3f0000 0 0 keyring _uid.0 : empty 13670439 I--Q-- 2 perm 1f3f0000 0 0 keyring _ses.1977 : 1/4 159d39b8 I--Q-- 6 perm 1f3f0000 0 0 keyring _ses.1976 : 1/4 3a14f259 I--Q-- 3 perm 1f3f0000 0 0 keyring _ses.1978 : 1/4 [Serial][Flags][Usage][Expiry][Permissions][UID][GID][TypeName][Description] :[Summary] |
*Source: linux_kernel_source/security/keys/proc.c:proc_keys_show()
The fields you see in the above file mostly come from
struct key, as defined in include/linux/key.h. Possible
flag values are shown in Listing 11.
Listing 11. Possible flag values of struct key fields
I Instantiated
R Revoked
D Dead
Q Contributes to user's quota
U Under construction by callback to user-space
N Negative key
|
/proc/key-users
Listing 12 shows the /proc/key-users file.
Listing 12. The /proc/key-users file
[root@phoenix set.5]# cat /proc/key-users
0: 6 5/5 3/100 90/10000
43: 2 2/2 2/100 56/10000
48: 2 2/2 2/100 56/10000
81: 2 2/2 2/100 56/10000
786: 4 4/4 4/100 113/10000
|
The fields shown in Listing 13 correspond to each line sequentially.
Listing 13. Fields of /proc/key-users file
<UID> User ID <usage> Usage count <inst>/<keys> Total number of keys and number instantiated <keys>/<max> Key count quota <bytes><max> Key size quota |
*Source: linux_kernel_source/security/keys/proc.c:proc_key_users_show()
Mostly these are fields of struct key_user defined in
security/keys/internal.h.
The Linux key retention service is a new mechanism introduced to hold security-related information for fast access by the Linux kernel. It is still in its early phases and is just beginning to gain wider acceptance. OpenAFS uses the Linux key retention service to implement process authentication group (PAG), and NFSv4 and MIT Kerberos use it also. The Linux key retention service is still under development and may be modified or enhanced in the future.
| Description | Name | Size | Download method |
|---|---|---|---|
| Sample app using the Linux key retention service | key.retention.services.zip | 4KB | HTTP |
Information about download methods
Learn
-
"Securing Linux"
(developerWorks, July 2004) is a three-part comprehensive introduction to Linux
security.
-
"Kernel command
using Linux system calls"
(developerWorks, March 2007) introduces Linux system calls and explains how a
syscall travels from user-space to the kernel.
- See
Documentation/keys.txt
and
Documentation/keys-request-key.txt
to learn more about keys and key creation in the Linux 2.6 kernel.
- Linux key implementation sources
are the Linux kernel APIs for managing keys.
- David Howells is the creator of the Linux key
retention service. View the
slides from his talk
at the 2006 Ottawa Linux Symposium.
-
"Kernel key management" offers more
about the Linux kernel APIs for managing keys.
- OpenAFS uses the Linux key retention service
for its process authentication group (PAG) implementation. View the
source.
- In the
developerWorks Linux zone,
find more resources for Linux developers.
- Stay current with
developerWorks technical events and Webcasts.
Get products and technologies
- Download the
keyutils package to get
started with the Linux key retention service.
- With
IBM trial software,
available for download directly from developerWorks, build your next development
project on Linux.
Discuss
- Check out
developerWorks
blogs and
get involved in the
developerWorks community.

Avinesh Kumar works as a System Software Engineer for the Andrew File System Team at the IBM Software Labs in Pune, India. He works with kernel- and user-level debugging of dumps and crashes, as well as reported bugs on the Linux, AIX, and Solaris platforms. Avinesh has an MCA from the Department of Computer Science at the University of Pune. He is a Linux enthusiast who spends his spare time exploring the Linux kernel on his Fedora Core 6 box.

Sandesh Chopdekar works as a Staff Software Engineer for IBM, specializing in distributed filesystems and networking. He is currently working in the MCP project in LTC in Pune, India. Prior to joining IBM, Sandesh worked for a subsidiary of Citicorp. He holds a BS degree in chemistry from Mumbai University.





