blob: be5067ee25208c70d254725cd0b28d94fdfdd64f [file] [log] [blame]
======================
CRYPTOGRAPHIC KEY TYPE
======================
Contents:
- Overview.
- Key identification.
- Accessing crypto keys.
- Signature verification.
- Implementing crypto parsers.
- Implementing crypto subtypes.
- Initial PGP key preloading.
========
OVERVIEW
========
The "crypto" key type is designed to be a container for cryptographic keys,
without imposing any particular restrictions on the form of the cryptography or
the key.
The crypto key is given a subtype that defines what sort of data is associated
with the key and provides operations to describe and destroy it. However, no
requirement is made that the key data actually be loaded into the key.
The crypto key also has a number of data parsers registered with it. The data
parsers are responsible for extracing information the blobs of data passed to
the instantiator function. The first data parser that recognises the blob gets
to set the subtype of the key and define the operations that can be done on
that key.
Completely in-kernel key retention and operation subtypes and parsers can be
defined, but it would also be possible to provide access to cryptographic
hardware (such as a TPM) that might be used to both retain the relevant key and
perform operations using that key. In such a case, the crypto key would then
merely be an interface to the TPM driver.
==================
KEY IDENTIFICATION
==================
Because the identity of a key is not necessarily known and may not be easily
calculated when a crypto key is allocated, it may not be a simple matter to set
a key description to something that's useful for determining whether this is
the key you're looking for. Furthermore, it may be necessary to perform a
partial match upon the key identity.
To help with this, when a key is loaded, the parser calculates the key
fingerprint and stores a copy in the key structure.
The crypto key type's key matching function then performs more checks than just
the straightforward comparison of the description with the criterion string:
(1) If the criterion string is of the form "id:<hexdigits>" then the match
function will examine a key's fingerprint to see if the hex digits given
after the "id:" match the tail. For instance:
keyctl search @s crypto id:5acc2142
will match a key with fingerprint:
1A00 2040 7601 7889 DE11 882C 3823 04AD 5ACC 2142
(2) If the criterion string is of the form "<subtype>:<hexdigits>" then the
match will match the ID as in (1), but with the added restriction that
only keys of the specified subtype (e.g. dsa or rsa) will be matched. For
instance:
keyctl search @s crypto dsa:5acc2142
Looking in /proc/keys, the last 8 hex digits of the key fingerprint are
displayed, along with the subtype:
1a39e171 I----- 1 perm 3f010000 0 0 crypto modsign.0: DSA 5acc2142 []
=====================
ACCESSING CRYPTO KEYS
=====================
To access crypto keys from within the kernel, the following inclusion is
required:
#include <keys/crypto-type.h>
This gives access to the key type:
struct key_type key_type_crypto;
SIGNATURE VERIFICATION
----------------------
The four operations that can perform cryptographic signature verification,
using one of a set of keys to provide the public key:
(1) Begin verification procedure.
struct crypto_key_verify_context *
verify_sig_begin(struct key *keyring, const void *sig, size_t siglen);
This function sets up a verification context from the information in the
signature and looks for a suitable key in the keyring. The signature blob
must be presented again at the end of the procedure. The keys will be
checked against parameters in the signature, and if the matching one is
not found then -ENOKEY will be returned.
The hashing algorithm, if such a thing applies, will be determined from
information in the signature and the appropriate crypto module will be
used. -ENOPKG will be returned if the hash algorithm is unavailable.
The return value is an opaque pointer to be passed to the other functions,
or a negative error code.
(2) Indicate data to be verified.
int verify_sig_add_data(struct crypto_key_verify_context *ctx,
const void *data, size_t datalen);
This function is used to shovel data to the verification procedure so that
it can load it into the hash, pass it to hardware or whatever is
appropriate for the algorithm being employed.
The data is not canonicalised for the document type specified in the
signature. The caller must do that.
It will return 0 if successful and a negative error code if not.
(3) Complete the verification process.
int verify_sig_end(struct crypto_key_verify_context *ctx,
const void *sig, size_t siglen);
This function performs the actual signature verification step and cleans
up the resources allocated at the beginning. The signature must be
presented again as some of the data therein may need to be added to the
internal hash.
It will return -EKEYREJECTED if the signature didn't match, 0 if
successful and may return other errors as appropriate.
(4) Cancel the verification process.
void verify_sig_cancel(struct crypto_key_verify_context *ctx);
This function cleans up the resources allocated at the beginning. This is
not necessary if verify_sig_end() was called.
===========================
IMPLEMENTING CRYPTO PARSERS
===========================
The crypto key type keeps a list of registered data parsers. An example of
such a parser is one that parses OpenPGP packet formatted data [RFC 4880].
During key instantiation each parser in the list is tried until one doesn't
return -EBADMSG.
The parser definition structure looks like the following:
struct crypto_key_parser {
struct module *owner;
const char *name;
int (*instantiate)(struct key *key,
const void *data, size_t datalen);
struct crypto_key_verify_context *(*verify_sig_begin)(
struct key *keyring, const u8 *sig, size_t siglen);
};
The owner and name fields should be set to the owning module and the name of
the parser.
There are a number of operations defined by the parser. They are all optional,
but it is expected that at least one will be defined.
(1) instantiate().
The arguments are the same as for the instantiate function in the key
type. 'key' is the crypto key being instantiated; data and datalen are
the instantiation data, presumably containing cryptographic key data, and
the length of that data.
If the data format is not recognised, -EBADMSG should be returned. If it
is recognised, but the key cannot for some reason be set up, some other
negative error code should be returned.
If the key can be successfully set up, then key->payload should be set to
point to the retained data, key->type_data.p[0] should be set to point to
the subtype chosen and key->type_data.p[1] should be set to point to a
copy of the key's identity string and 0 should be returned.
The key's identity string may be partially matched upon. For a public-key
algorithm such as RSA and DSA this will likely be a printable hex version
of the key's fingerprint.
(2) verify_sig_begin().
This is similar in concept to the instantiate() function, except that it
is given a signature blob to parse rather than a key data blob.
If the data format is not recognised, -EBADMSG should be returned. If it
is recognised, but the signature verification process cannot for some
reason be set up, some other negative error code should be returned.
-ENOKEY should be used to indicate that no matching key is available and
-ENOPKG should be returned if the hash algorithm or the verification
algorithm are unavailable.
If successful, the parser should allocate a verification context and embed
the following struct in it:
struct crypto_key_verify_context {
struct key *key;
int (*add_data)(struct crypto_key_verify_context *ctx,
const void *data, size_t datalen);
int (*end)(struct crypto_key_verify_context *ctx,
const u8 *sig, size_t siglen);
void (*cancel)(struct crypto_key_verify_context *ctx);
};
and return a pointer to this to the caller, who will then pass it to the
verification operation wrappers described in the "Signature Verification"
section. The three operation pointers here correspond exactly to those
wrappers and are all mandatory. container_of() should be used to retrieve
the actual context.
Note that the crypto key type retains a reference on the parser module for
the lifetime of this context, though the operation pointers need not point
into this module.
The parser should also record a pointer to the key selected and take a
reference on that key with key_get().
Functions are provided to register and unregister parsers:
int register_crypto_key_parser(struct crypto_key_parser *parser);
void unregister_crypto_key_parser(struct crypto_key_parser *subtype);
Parsers may not have the same name. The names are only used for displaying in
debugging messages.
============================
IMPLEMENTING CRYPTO SUBTYPES
============================
The parser selects the appropriate subtype directly and sets it on the key; the
crypto key then retains a reference on the subtype module (which means the
parser can be removed thereafter).
The subtype definition structure looks like the following:
struct crypto_key_subtype {
struct module *owner;
const char *name;
void (*describe)(const struct key *key, struct seq_file *m);
void (*destroy)(void *payload);
};
The owner and name fields should be set to the owning module and the name of
the subtype.
There are a number of operations defined by the subtype:
(1) describe().
Mandatory. This allows the subtype to display something in /proc/keys
against the key. For instance the name of the public key algorithm type
could be displayed. The key type will display the tail of the key
identity string after this.
(2) destroy().
Mandatory. This should free the memory associated with the key. The
crypto key will look after freeing the fingerprint and releasing the
reference on the subtype module.
=======================
INITIAL PGP KEY LOADING
=======================
A function is provided to perform an initial load of a set of public keys bound
into a PGP packet format blob:
int preload_pgp_keys(const u8 *pgpdata, size_t pgpdatalen,
struct key *keyring);
This takes the blob of data defined by pgpdata and pgpdatalen, extracts keys
from them and adds them to the specified keyring. The keys are labelled with a
description generated from the fingerprint and last user ID of each key. The
description is required to prevent all but the last key being discarded when
the keys are linked into the keyring.
This function is only available during initial kernel set up.