| =================== | |
| Key Request Service | |
| =================== | |
| The key request service is part of the key retention service (refer to | |
| Documentation/security/keys/core.rst). This document explains more fully how | |
| the requesting algorithm works. | |
| The process starts by either the kernel requesting a service by calling | |
| ``request_key*()``:: | |
| struct key *request_key(const struct key_type *type, | |
| const char *description, | |
| const char *callout_info); | |
| or:: | |
| struct key *request_key_with_auxdata(const struct key_type *type, | |
| const char *description, | |
| const char *callout_info, | |
| size_t callout_len, | |
| void *aux); | |
| or:: | |
| struct key *request_key_async(const struct key_type *type, | |
| const char *description, | |
| const char *callout_info, | |
| size_t callout_len); | |
| or:: | |
| struct key *request_key_async_with_auxdata(const struct key_type *type, | |
| const char *description, | |
| const char *callout_info, | |
| size_t callout_len, | |
| void *aux); | |
| Or by userspace invoking the request_key system call:: | |
| key_serial_t request_key(const char *type, | |
| const char *description, | |
| const char *callout_info, | |
| key_serial_t dest_keyring); | |
| The main difference between the access points is that the in-kernel interface | |
| does not need to link the key to a keyring to prevent it from being immediately | |
| destroyed. The kernel interface returns a pointer directly to the key, and | |
| it's up to the caller to destroy the key. | |
| The request_key*_with_auxdata() calls are like the in-kernel request_key*() | |
| calls, except that they permit auxiliary data to be passed to the upcaller (the | |
| default is NULL). This is only useful for those key types that define their | |
| own upcall mechanism rather than using /sbin/request-key. | |
| The two async in-kernel calls may return keys that are still in the process of | |
| being constructed. The two non-async ones will wait for construction to | |
| complete first. | |
| The userspace interface links the key to a keyring associated with the process | |
| to prevent the key from going away, and returns the serial number of the key to | |
| the caller. | |
| The following example assumes that the key types involved don't define their | |
| own upcall mechanisms. If they do, then those should be substituted for the | |
| forking and execution of /sbin/request-key. | |
| The Process | |
| =========== | |
| A request proceeds in the following manner: | |
| 1) Process A calls request_key() [the userspace syscall calls the kernel | |
| interface]. | |
| 2) request_key() searches the process's subscribed keyrings to see if there's | |
| a suitable key there. If there is, it returns the key. If there isn't, | |
| and callout_info is not set, an error is returned. Otherwise the process | |
| proceeds to the next step. | |
| 3) request_key() sees that A doesn't have the desired key yet, so it creates | |
| two things: | |
| a) An uninstantiated key U of requested type and description. | |
| b) An authorisation key V that refers to key U and notes that process A | |
| is the context in which key U should be instantiated and secured, and | |
| from which associated key requests may be satisfied. | |
| 4) request_key() then forks and executes /sbin/request-key with a new session | |
| keyring that contains a link to auth key V. | |
| 5) /sbin/request-key assumes the authority associated with key U. | |
| 6) /sbin/request-key execs an appropriate program to perform the actual | |
| instantiation. | |
| 7) The program may want to access another key from A's context (say a | |
| Kerberos TGT key). It just requests the appropriate key, and the keyring | |
| search notes that the session keyring has auth key V in its bottom level. | |
| This will permit it to then search the keyrings of process A with the | |
| UID, GID, groups and security info of process A as if it was process A, | |
| and come up with key W. | |
| 8) The program then does what it must to get the data with which to | |
| instantiate key U, using key W as a reference (perhaps it contacts a | |
| Kerberos server using the TGT) and then instantiates key U. | |
| 9) Upon instantiating key U, auth key V is automatically revoked so that it | |
| may not be used again. | |
| 10) The program then exits 0 and request_key() deletes key V and returns key | |
| U to the caller. | |
| This also extends further. If key W (step 7 above) didn't exist, key W would | |
| be created uninstantiated, another auth key (X) would be created (as per step | |
| 3) and another copy of /sbin/request-key spawned (as per step 4); but the | |
| context specified by auth key X will still be process A, as it was in auth key | |
| V. | |
| This is because process A's keyrings can't simply be attached to | |
| /sbin/request-key at the appropriate places because (a) execve will discard two | |
| of them, and (b) it requires the same UID/GID/Groups all the way through. | |
| Negative Instantiation And Rejection | |
| ==================================== | |
| Rather than instantiating a key, it is possible for the possessor of an | |
| authorisation key to negatively instantiate a key that's under construction. | |
| This is a short duration placeholder that causes any attempt at re-requesting | |
| the key whilst it exists to fail with error ENOKEY if negated or the specified | |
| error if rejected. | |
| This is provided to prevent excessive repeated spawning of /sbin/request-key | |
| processes for a key that will never be obtainable. | |
| Should the /sbin/request-key process exit anything other than 0 or die on a | |
| signal, the key under construction will be automatically negatively | |
| instantiated for a short amount of time. | |
| The Search Algorithm | |
| ==================== | |
| A search of any particular keyring proceeds in the following fashion: | |
| 1) When the key management code searches for a key (keyring_search_aux) it | |
| firstly calls key_permission(SEARCH) on the keyring it's starting with, | |
| if this denies permission, it doesn't search further. | |
| 2) It considers all the non-keyring keys within that keyring and, if any key | |
| matches the criteria specified, calls key_permission(SEARCH) on it to see | |
| if the key is allowed to be found. If it is, that key is returned; if | |
| not, the search continues, and the error code is retained if of higher | |
| priority than the one currently set. | |
| 3) It then considers all the keyring-type keys in the keyring it's currently | |
| searching. It calls key_permission(SEARCH) on each keyring, and if this | |
| grants permission, it recurses, executing steps (2) and (3) on that | |
| keyring. | |
| The process stops immediately a valid key is found with permission granted to | |
| use it. Any error from a previous match attempt is discarded and the key is | |
| returned. | |
| When search_process_keyrings() is invoked, it performs the following searches | |
| until one succeeds: | |
| 1) If extant, the process's thread keyring is searched. | |
| 2) If extant, the process's process keyring is searched. | |
| 3) The process's session keyring is searched. | |
| 4) If the process has assumed the authority associated with a request_key() | |
| authorisation key then: | |
| a) If extant, the calling process's thread keyring is searched. | |
| b) If extant, the calling process's process keyring is searched. | |
| c) The calling process's session keyring is searched. | |
| The moment one succeeds, all pending errors are discarded and the found key is | |
| returned. | |
| Only if all these fail does the whole thing fail with the highest priority | |
| error. Note that several errors may have come from LSM. | |
| The error priority is:: | |
| EKEYREVOKED > EKEYEXPIRED > ENOKEY | |
| EACCES/EPERM are only returned on a direct search of a specific keyring where | |
| the basal keyring does not grant Search permission. |