doc: ReSTify keys-request-key.txt

Adjusts for ReST markup and moves under keys security devel index.

Cc: David Howells <dhowells@redhat.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Jonathan Corbet <corbet@lwn.net>
diff --git a/Documentation/security/keys/request-key.rst b/Documentation/security/keys/request-key.rst
new file mode 100644
index 0000000..5cdcee2
--- /dev/null
+++ b/Documentation/security/keys/request-key.rst
@@ -0,0 +1,199 @@
+===================
+Key Request Service
+===================
+
+The key request service is part of the key retention service (refer to
+Documentation/security/keys.txt).  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.