Kyle Swenson | 8d8f654 | 2021-03-15 11:02:55 -0600 | [diff] [blame^] | 1 | ============================================= |
| 2 | ASYMMETRIC / PUBLIC-KEY CRYPTOGRAPHY KEY TYPE |
| 3 | ============================================= |
| 4 | |
| 5 | Contents: |
| 6 | |
| 7 | - Overview. |
| 8 | - Key identification. |
| 9 | - Accessing asymmetric keys. |
| 10 | - Signature verification. |
| 11 | - Asymmetric key subtypes. |
| 12 | - Instantiation data parsers. |
| 13 | |
| 14 | |
| 15 | ======== |
| 16 | OVERVIEW |
| 17 | ======== |
| 18 | |
| 19 | The "asymmetric" key type is designed to be a container for the keys used in |
| 20 | public-key cryptography, without imposing any particular restrictions on the |
| 21 | form or mechanism of the cryptography or form of the key. |
| 22 | |
| 23 | The asymmetric key is given a subtype that defines what sort of data is |
| 24 | associated with the key and provides operations to describe and destroy it. |
| 25 | However, no requirement is made that the key data actually be stored in the |
| 26 | key. |
| 27 | |
| 28 | A completely in-kernel key retention and operation subtype can be defined, but |
| 29 | it would also be possible to provide access to cryptographic hardware (such as |
| 30 | a TPM) that might be used to both retain the relevant key and perform |
| 31 | operations using that key. In such a case, the asymmetric key would then |
| 32 | merely be an interface to the TPM driver. |
| 33 | |
| 34 | Also provided is the concept of a data parser. Data parsers are responsible |
| 35 | for extracting information from the blobs of data passed to the instantiation |
| 36 | function. The first data parser that recognises the blob gets to set the |
| 37 | subtype of the key and define the operations that can be done on that key. |
| 38 | |
| 39 | A data parser may interpret the data blob as containing the bits representing a |
| 40 | key, or it may interpret it as a reference to a key held somewhere else in the |
| 41 | system (for example, a TPM). |
| 42 | |
| 43 | |
| 44 | ================== |
| 45 | KEY IDENTIFICATION |
| 46 | ================== |
| 47 | |
| 48 | If a key is added with an empty name, the instantiation data parsers are given |
| 49 | the opportunity to pre-parse a key and to determine the description the key |
| 50 | should be given from the content of the key. |
| 51 | |
| 52 | This can then be used to refer to the key, either by complete match or by |
| 53 | partial match. The key type may also use other criteria to refer to a key. |
| 54 | |
| 55 | The asymmetric key type's match function can then perform a wider range of |
| 56 | comparisons than just the straightforward comparison of the description with |
| 57 | the criterion string: |
| 58 | |
| 59 | (1) If the criterion string is of the form "id:<hexdigits>" then the match |
| 60 | function will examine a key's fingerprint to see if the hex digits given |
| 61 | after the "id:" match the tail. For instance: |
| 62 | |
| 63 | keyctl search @s asymmetric id:5acc2142 |
| 64 | |
| 65 | will match a key with fingerprint: |
| 66 | |
| 67 | 1A00 2040 7601 7889 DE11 882C 3823 04AD 5ACC 2142 |
| 68 | |
| 69 | (2) If the criterion string is of the form "<subtype>:<hexdigits>" then the |
| 70 | match will match the ID as in (1), but with the added restriction that |
| 71 | only keys of the specified subtype (e.g. tpm) will be matched. For |
| 72 | instance: |
| 73 | |
| 74 | keyctl search @s asymmetric tpm:5acc2142 |
| 75 | |
| 76 | Looking in /proc/keys, the last 8 hex digits of the key fingerprint are |
| 77 | displayed, along with the subtype: |
| 78 | |
| 79 | 1a39e171 I----- 1 perm 3f010000 0 0 asymmetri modsign.0: DSA 5acc2142 [] |
| 80 | |
| 81 | |
| 82 | ========================= |
| 83 | ACCESSING ASYMMETRIC KEYS |
| 84 | ========================= |
| 85 | |
| 86 | For general access to asymmetric keys from within the kernel, the following |
| 87 | inclusion is required: |
| 88 | |
| 89 | #include <crypto/public_key.h> |
| 90 | |
| 91 | This gives access to functions for dealing with asymmetric / public keys. |
| 92 | Three enums are defined there for representing public-key cryptography |
| 93 | algorithms: |
| 94 | |
| 95 | enum pkey_algo |
| 96 | |
| 97 | digest algorithms used by those: |
| 98 | |
| 99 | enum pkey_hash_algo |
| 100 | |
| 101 | and key identifier representations: |
| 102 | |
| 103 | enum pkey_id_type |
| 104 | |
| 105 | Note that the key type representation types are required because key |
| 106 | identifiers from different standards aren't necessarily compatible. For |
| 107 | instance, PGP generates key identifiers by hashing the key data plus some |
| 108 | PGP-specific metadata, whereas X.509 has arbitrary certificate identifiers. |
| 109 | |
| 110 | The operations defined upon a key are: |
| 111 | |
| 112 | (1) Signature verification. |
| 113 | |
| 114 | Other operations are possible (such as encryption) with the same key data |
| 115 | required for verification, but not currently supported, and others |
| 116 | (eg. decryption and signature generation) require extra key data. |
| 117 | |
| 118 | |
| 119 | SIGNATURE VERIFICATION |
| 120 | ---------------------- |
| 121 | |
| 122 | An operation is provided to perform cryptographic signature verification, using |
| 123 | an asymmetric key to provide or to provide access to the public key. |
| 124 | |
| 125 | int verify_signature(const struct key *key, |
| 126 | const struct public_key_signature *sig); |
| 127 | |
| 128 | The caller must have already obtained the key from some source and can then use |
| 129 | it to check the signature. The caller must have parsed the signature and |
| 130 | transferred the relevant bits to the structure pointed to by sig. |
| 131 | |
| 132 | struct public_key_signature { |
| 133 | u8 *digest; |
| 134 | u8 digest_size; |
| 135 | enum pkey_hash_algo pkey_hash_algo : 8; |
| 136 | u8 nr_mpi; |
| 137 | union { |
| 138 | MPI mpi[2]; |
| 139 | ... |
| 140 | }; |
| 141 | }; |
| 142 | |
| 143 | The algorithm used must be noted in sig->pkey_hash_algo, and all the MPIs that |
| 144 | make up the actual signature must be stored in sig->mpi[] and the count of MPIs |
| 145 | placed in sig->nr_mpi. |
| 146 | |
| 147 | In addition, the data must have been digested by the caller and the resulting |
| 148 | hash must be pointed to by sig->digest and the size of the hash be placed in |
| 149 | sig->digest_size. |
| 150 | |
| 151 | The function will return 0 upon success or -EKEYREJECTED if the signature |
| 152 | doesn't match. |
| 153 | |
| 154 | The function may also return -ENOTSUPP if an unsupported public-key algorithm |
| 155 | or public-key/hash algorithm combination is specified or the key doesn't |
| 156 | support the operation; -EBADMSG or -ERANGE if some of the parameters have weird |
| 157 | data; or -ENOMEM if an allocation can't be performed. -EINVAL can be returned |
| 158 | if the key argument is the wrong type or is incompletely set up. |
| 159 | |
| 160 | |
| 161 | ======================= |
| 162 | ASYMMETRIC KEY SUBTYPES |
| 163 | ======================= |
| 164 | |
| 165 | Asymmetric keys have a subtype that defines the set of operations that can be |
| 166 | performed on that key and that determines what data is attached as the key |
| 167 | payload. The payload format is entirely at the whim of the subtype. |
| 168 | |
| 169 | The subtype is selected by the key data parser and the parser must initialise |
| 170 | the data required for it. The asymmetric key retains a reference on the |
| 171 | subtype module. |
| 172 | |
| 173 | The subtype definition structure can be found in: |
| 174 | |
| 175 | #include <keys/asymmetric-subtype.h> |
| 176 | |
| 177 | and looks like the following: |
| 178 | |
| 179 | struct asymmetric_key_subtype { |
| 180 | struct module *owner; |
| 181 | const char *name; |
| 182 | |
| 183 | void (*describe)(const struct key *key, struct seq_file *m); |
| 184 | void (*destroy)(void *payload); |
| 185 | int (*verify_signature)(const struct key *key, |
| 186 | const struct public_key_signature *sig); |
| 187 | }; |
| 188 | |
| 189 | Asymmetric keys point to this with their payload[asym_subtype] member. |
| 190 | |
| 191 | The owner and name fields should be set to the owning module and the name of |
| 192 | the subtype. Currently, the name is only used for print statements. |
| 193 | |
| 194 | There are a number of operations defined by the subtype: |
| 195 | |
| 196 | (1) describe(). |
| 197 | |
| 198 | Mandatory. This allows the subtype to display something in /proc/keys |
| 199 | against the key. For instance the name of the public key algorithm type |
| 200 | could be displayed. The key type will display the tail of the key |
| 201 | identity string after this. |
| 202 | |
| 203 | (2) destroy(). |
| 204 | |
| 205 | Mandatory. This should free the memory associated with the key. The |
| 206 | asymmetric key will look after freeing the fingerprint and releasing the |
| 207 | reference on the subtype module. |
| 208 | |
| 209 | (3) verify_signature(). |
| 210 | |
| 211 | Optional. These are the entry points for the key usage operations. |
| 212 | Currently there is only the one defined. If not set, the caller will be |
| 213 | given -ENOTSUPP. The subtype may do anything it likes to implement an |
| 214 | operation, including offloading to hardware. |
| 215 | |
| 216 | |
| 217 | ========================== |
| 218 | INSTANTIATION DATA PARSERS |
| 219 | ========================== |
| 220 | |
| 221 | The asymmetric key type doesn't generally want to store or to deal with a raw |
| 222 | blob of data that holds the key data. It would have to parse it and error |
| 223 | check it each time it wanted to use it. Further, the contents of the blob may |
| 224 | have various checks that can be performed on it (eg. self-signatures, validity |
| 225 | dates) and may contain useful data about the key (identifiers, capabilities). |
| 226 | |
| 227 | Also, the blob may represent a pointer to some hardware containing the key |
| 228 | rather than the key itself. |
| 229 | |
| 230 | Examples of blob formats for which parsers could be implemented include: |
| 231 | |
| 232 | - OpenPGP packet stream [RFC 4880]. |
| 233 | - X.509 ASN.1 stream. |
| 234 | - Pointer to TPM key. |
| 235 | - Pointer to UEFI key. |
| 236 | |
| 237 | During key instantiation each parser in the list is tried until one doesn't |
| 238 | return -EBADMSG. |
| 239 | |
| 240 | The parser definition structure can be found in: |
| 241 | |
| 242 | #include <keys/asymmetric-parser.h> |
| 243 | |
| 244 | and looks like the following: |
| 245 | |
| 246 | struct asymmetric_key_parser { |
| 247 | struct module *owner; |
| 248 | const char *name; |
| 249 | |
| 250 | int (*parse)(struct key_preparsed_payload *prep); |
| 251 | }; |
| 252 | |
| 253 | The owner and name fields should be set to the owning module and the name of |
| 254 | the parser. |
| 255 | |
| 256 | There is currently only a single operation defined by the parser, and it is |
| 257 | mandatory: |
| 258 | |
| 259 | (1) parse(). |
| 260 | |
| 261 | This is called to preparse the key from the key creation and update paths. |
| 262 | In particular, it is called during the key creation _before_ a key is |
| 263 | allocated, and as such, is permitted to provide the key's description in |
| 264 | the case that the caller declines to do so. |
| 265 | |
| 266 | The caller passes a pointer to the following struct with all of the fields |
| 267 | cleared, except for data, datalen and quotalen [see |
| 268 | Documentation/security/keys.txt]. |
| 269 | |
| 270 | struct key_preparsed_payload { |
| 271 | char *description; |
| 272 | void *payload[4]; |
| 273 | const void *data; |
| 274 | size_t datalen; |
| 275 | size_t quotalen; |
| 276 | }; |
| 277 | |
| 278 | The instantiation data is in a blob pointed to by data and is datalen in |
| 279 | size. The parse() function is not permitted to change these two values at |
| 280 | all, and shouldn't change any of the other values _unless_ they are |
| 281 | recognise the blob format and will not return -EBADMSG to indicate it is |
| 282 | not theirs. |
| 283 | |
| 284 | If the parser is happy with the blob, it should propose a description for |
| 285 | the key and attach it to ->description, ->payload[asym_subtype] should be |
| 286 | set to point to the subtype to be used, ->payload[asym_crypto] should be |
| 287 | set to point to the initialised data for that subtype, |
| 288 | ->payload[asym_key_ids] should point to one or more hex fingerprints and |
| 289 | quotalen should be updated to indicate how much quota this key should |
| 290 | account for. |
| 291 | |
| 292 | When clearing up, the data attached to ->payload[asym_key_ids] and |
| 293 | ->description will be kfree()'d and the data attached to |
| 294 | ->payload[asm_crypto] will be passed to the subtype's ->destroy() method |
| 295 | to be disposed of. A module reference for the subtype pointed to by |
| 296 | ->payload[asym_subtype] will be put. |
| 297 | |
| 298 | |
| 299 | If the data format is not recognised, -EBADMSG should be returned. If it |
| 300 | is recognised, but the key cannot for some reason be set up, some other |
| 301 | negative error code should be returned. On success, 0 should be returned. |
| 302 | |
| 303 | The key's fingerprint string may be partially matched upon. For a |
| 304 | public-key algorithm such as RSA and DSA this will likely be a printable |
| 305 | hex version of the key's fingerprint. |
| 306 | |
| 307 | Functions are provided to register and unregister parsers: |
| 308 | |
| 309 | int register_asymmetric_key_parser(struct asymmetric_key_parser *parser); |
| 310 | void unregister_asymmetric_key_parser(struct asymmetric_key_parser *subtype); |
| 311 | |
| 312 | Parsers may not have the same name. The names are otherwise only used for |
| 313 | displaying in debugging messages. |