Get started with the Linux key retention service

Create a new key type using Linux kernel APIs

The Linux® key retention service introduced with Linux 2.6 is a great new way to handle authentication, cryptography, cross-domain user mappings, and other security concerns for the Linux platform. Learn the components of the Linux key retention service and get an understanding of its usage with a working sample application.

Avinesh Kumar, Software Engineer, IBM

Photo of Avinesh KumarAvinesh 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.


developerWorks Contributing author
        level

Sandesh Chopdekar, Software Engineer, IBM

Photo of Sandesh ChopdekarSandesh Chopdekar works as a Staff Software Engineer for IBM, specializing in distributed filesystems and networking. Prior to joining IBM, Sandesh worked for a subsidiary of Citicorp. He holds a BS degree in chemistry from Mumbai University.



11 April 2007

Also available in Russian Japanese

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.

What is a key?

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 */
      ....
      ....
};

Attributes of a key

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 in include/linux/key.h. Some important fields of the key_type structure are shown in Listing 2.
    Listing 2. Important fields of key_type
    struct 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. A key_type can define the following operations:
    • instantiate creates a new key of a specified type.
    • describe prints text describing the key.
    • match searches a key based on its description.
    • destroy clears all data related to a key.
    • request_key searches for a key.
    • revoke clears key data and changes the state of the key to REVOKED.
    • read reads key data.
    • update modifies 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:
    • View allows the possessor to view key attributes.
    • Read allows the possessor to read the key and lists the key for a keyring.
    • Write allows the possessor to modify the payload for a key or keyring and to modify linked keys.
    • Search allows the possessor to search keyrings and find keys.
    • Link allows the possessor to link a particular key or keyring to a keyring.
    • Set Attribute allows 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_type are 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: The key_type is unregistered.

Key types

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:

  1. Thread-specific
  2. Process-specific
  3. Session-specific
  4. User-specific session
  5. User-default session
  6. Group-specific (not yet implemented)

Quotas

There is a limit on the number of keys and keyrings a user can own (the key count quota) and also on the space used in the key description and payload (the key size quota). Process-specific and thread-specific keyrings are not considered part of the user's quota.

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.


Three new syscalls

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_DESCRIBE describes a key.
  • KEYCTL_READ reads payload data from a key.
  • KEYCTL_UPDATE updates the specified key.
  • KEYCTL_LINK links a key into a keyring.
  • KEYCTL_UNLINK unlinks a key or keyring from another keyring.
  • KEYCTL_JOIN_SESSION_KEYRING replaces a session keyring with a new one.
  • KEYCTL_REVOKE revokes a key.
  • KEYCTL_CHOWN changes the ownership of a key.
  • KEYCTL_SETPERM changes the permissions mask on a key.
  • KEYCTL_CLEAR clears out a keyring.
  • KEYCTL_SEARCH searches a keyring tree for a key.
  • KEYCTL_INSTANTIATE instantiates a partially constructed key.
  • KEYCTL_NEGATE negatively 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.


Kernel APIs to manage keys

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 EEXIT if 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);

Enabling key services

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.


Create a new key type

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.


Using the module

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"

Proc files related to keys

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.


In conclusion

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.


Download

DescriptionNameSize
Sample app using the Linux key retention servicekey.retention.services.zip4KB

Resources

Learn

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

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Linux on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Linux
ArticleID=208754
ArticleTitle=Get started with the Linux key retention service
publish-date=04112007