| ============================================= | |
| ASYMMETRIC / PUBLIC-KEY CRYPTOGRAPHY KEY TYPE | |
| ============================================= | |
| Contents: | |
| - Overview. | |
| - Key identification. | |
| - Accessing asymmetric keys. | |
| - Signature verification. | |
| - Asymmetric key subtypes. | |
| - Instantiation data parsers. | |
| ======== | |
| OVERVIEW | |
| ======== | |
| The "asymmetric" key type is designed to be a container for the keys used in | |
| public-key cryptography, without imposing any particular restrictions on the | |
| form or mechanism of the cryptography or form of the key. | |
| The asymmetric 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 stored in the | |
| key. | |
| A completely in-kernel key retention and operation subtype 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 asymmetric key would then | |
| merely be an interface to the TPM driver. | |
| Also provided is the concept of a data parser. Data parsers are responsible | |
| for extracting information from the blobs of data passed to the instantiation | |
| 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. | |
| A data parser may interpret the data blob as containing the bits representing a | |
| key, or it may interpret it as a reference to a key held somewhere else in the | |
| system (for example, a TPM). | |
| ================== | |
| KEY IDENTIFICATION | |
| ================== | |
| If a key is added with an empty name, the instantiation data parsers are given | |
| the opportunity to pre-parse a key and to determine the description the key | |
| should be given from the content of the key. | |
| This can then be used to refer to the key, either by complete match or by | |
| partial match. The key type may also use other criteria to refer to a key. | |
| The asymmetric key type's match function can then perform a wider range of | |
| comparisons 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 asymmetric 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. tpm) will be matched. For | |
| instance: | |
| keyctl search @s asymmetric tpm: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 asymmetri modsign.0: DSA 5acc2142 [] | |
| ========================= | |
| ACCESSING ASYMMETRIC KEYS | |
| ========================= | |
| For general access to asymmetric keys from within the kernel, the following | |
| inclusion is required: | |
| #include <crypto/public_key.h> | |
| This gives access to functions for dealing with asymmetric / public keys. | |
| Three enums are defined there for representing public-key cryptography | |
| algorithms: | |
| enum pkey_algo | |
| digest algorithms used by those: | |
| enum pkey_hash_algo | |
| and key identifier representations: | |
| enum pkey_id_type | |
| Note that the key type representation types are required because key | |
| identifiers from different standards aren't necessarily compatible. For | |
| instance, PGP generates key identifiers by hashing the key data plus some | |
| PGP-specific metadata, whereas X.509 has arbitrary certificate identifiers. | |
| The operations defined upon a key are: | |
| (1) Signature verification. | |
| Other operations are possible (such as encryption) with the same key data | |
| required for verification, but not currently supported, and others | |
| (eg. decryption and signature generation) require extra key data. | |
| SIGNATURE VERIFICATION | |
| ---------------------- | |
| An operation is provided to perform cryptographic signature verification, using | |
| an asymmetric key to provide or to provide access to the public key. | |
| int verify_signature(const struct key *key, | |
| const struct public_key_signature *sig); | |
| The caller must have already obtained the key from some source and can then use | |
| it to check the signature. The caller must have parsed the signature and | |
| transferred the relevant bits to the structure pointed to by sig. | |
| struct public_key_signature { | |
| u8 *digest; | |
| u8 digest_size; | |
| enum pkey_hash_algo pkey_hash_algo : 8; | |
| u8 nr_mpi; | |
| union { | |
| MPI mpi[2]; | |
| ... | |
| }; | |
| }; | |
| The algorithm used must be noted in sig->pkey_hash_algo, and all the MPIs that | |
| make up the actual signature must be stored in sig->mpi[] and the count of MPIs | |
| placed in sig->nr_mpi. | |
| In addition, the data must have been digested by the caller and the resulting | |
| hash must be pointed to by sig->digest and the size of the hash be placed in | |
| sig->digest_size. | |
| The function will return 0 upon success or -EKEYREJECTED if the signature | |
| doesn't match. | |
| The function may also return -ENOTSUPP if an unsupported public-key algorithm | |
| or public-key/hash algorithm combination is specified or the key doesn't | |
| support the operation; -EBADMSG or -ERANGE if some of the parameters have weird | |
| data; or -ENOMEM if an allocation can't be performed. -EINVAL can be returned | |
| if the key argument is the wrong type or is incompletely set up. | |
| ======================= | |
| ASYMMETRIC KEY SUBTYPES | |
| ======================= | |
| Asymmetric keys have a subtype that defines the set of operations that can be | |
| performed on that key and that determines what data is attached as the key | |
| payload. The payload format is entirely at the whim of the subtype. | |
| The subtype is selected by the key data parser and the parser must initialise | |
| the data required for it. The asymmetric key retains a reference on the | |
| subtype module. | |
| The subtype definition structure can be found in: | |
| #include <keys/asymmetric-subtype.h> | |
| and looks like the following: | |
| struct asymmetric_key_subtype { | |
| struct module *owner; | |
| const char *name; | |
| void (*describe)(const struct key *key, struct seq_file *m); | |
| void (*destroy)(void *payload); | |
| int (*verify_signature)(const struct key *key, | |
| const struct public_key_signature *sig); | |
| }; | |
| Asymmetric keys point to this with their type_data[0] member. | |
| The owner and name fields should be set to the owning module and the name of | |
| the subtype. Currently, the name is only used for print statements. | |
| 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 | |
| asymmetric key will look after freeing the fingerprint and releasing the | |
| reference on the subtype module. | |
| (3) verify_signature(). | |
| Optional. These are the entry points for the key usage operations. | |
| Currently there is only the one defined. If not set, the caller will be | |
| given -ENOTSUPP. The subtype may do anything it likes to implement an | |
| operation, including offloading to hardware. | |
| ========================== | |
| INSTANTIATION DATA PARSERS | |
| ========================== | |
| The asymmetric key type doesn't generally want to store or to deal with a raw | |
| blob of data that holds the key data. It would have to parse it and error | |
| check it each time it wanted to use it. Further, the contents of the blob may | |
| have various checks that can be performed on it (eg. self-signatures, validity | |
| dates) and may contain useful data about the key (identifiers, capabilities). | |
| Also, the blob may represent a pointer to some hardware containing the key | |
| rather than the key itself. | |
| Examples of blob formats for which parsers could be implemented include: | |
| - OpenPGP packet stream [RFC 4880]. | |
| - X.509 ASN.1 stream. | |
| - Pointer to TPM key. | |
| - Pointer to UEFI key. | |
| During key instantiation each parser in the list is tried until one doesn't | |
| return -EBADMSG. | |
| The parser definition structure can be found in: | |
| #include <keys/asymmetric-parser.h> | |
| and looks like the following: | |
| struct asymmetric_key_parser { | |
| struct module *owner; | |
| const char *name; | |
| int (*parse)(struct key_preparsed_payload *prep); | |
| }; | |
| The owner and name fields should be set to the owning module and the name of | |
| the parser. | |
| There is currently only a single operation defined by the parser, and it is | |
| mandatory: | |
| (1) parse(). | |
| This is called to preparse the key from the key creation and update paths. | |
| In particular, it is called during the key creation _before_ a key is | |
| allocated, and as such, is permitted to provide the key's description in | |
| the case that the caller declines to do so. | |
| The caller passes a pointer to the following struct with all of the fields | |
| cleared, except for data, datalen and quotalen [see | |
| Documentation/security/keys.txt]. | |
| struct key_preparsed_payload { | |
| char *description; | |
| void *type_data[2]; | |
| void *payload; | |
| const void *data; | |
| size_t datalen; | |
| size_t quotalen; | |
| }; | |
| The instantiation data is in a blob pointed to by data and is datalen in | |
| size. The parse() function is not permitted to change these two values at | |
| all, and shouldn't change any of the other values _unless_ they are | |
| recognise the blob format and will not return -EBADMSG to indicate it is | |
| not theirs. | |
| If the parser is happy with the blob, it should propose a description for | |
| the key and attach it to ->description, ->type_data[0] should be set to | |
| point to the subtype to be used, ->payload should be set to point to the | |
| initialised data for that subtype, ->type_data[1] should point to a hex | |
| fingerprint and quotalen should be updated to indicate how much quota this | |
| key should account for. | |
| When clearing up, the data attached to ->type_data[1] and ->description | |
| will be kfree()'d and the data attached to ->payload will be passed to the | |
| subtype's ->destroy() method to be disposed of. A module reference for | |
| the subtype pointed to by ->type_data[0] will be put. | |
| 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. On success, 0 should be returned. | |
| The key's fingerprint 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. | |
| Functions are provided to register and unregister parsers: | |
| int register_asymmetric_key_parser(struct asymmetric_key_parser *parser); | |
| void unregister_asymmetric_key_parser(struct asymmetric_key_parser *subtype); | |
| Parsers may not have the same name. The names are otherwise only used for | |
| displaying in debugging messages. |