Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

KEYS: Keyring asymmetric key restrict method with chaining

Add a restrict_link_by_key_or_keyring_chain link restriction that
searches for signing keys in the destination keyring in addition to the
signing key or keyring designated when the destination keyring was
created. Userspace enables this behavior by including the "chain" option
in the keyring restriction:

keyctl(KEYCTL_RESTRICT_KEYRING, keyring, "asymmetric",
"key_or_keyring:<signing key>:chain");

Signed-off-by: Mat Martineau <mathew.j.martineau@linux.intel.com>

+163 -54
+6 -1
Documentation/crypto/asymmetric-keys.txt
··· 343 343 (3) Restrict using a separate key or keyring 344 344 345 345 - Option string used with KEYCTL_RESTRICT_KEYRING: 346 - - "key_or_keyring:<key or keyring serial number>" 346 + - "key_or_keyring:<key or keyring serial number>[:chain]" 347 347 348 348 Whenever a key link is requested, the link will only succeed if the key 349 349 being linked is signed by one of the designated keys. This key may be 350 350 specified directly by providing a serial number for one asymmetric key, or 351 351 a group of keys may be searched for the signing key by providing the 352 352 serial number for a keyring. 353 + 354 + When the "chain" option is provided at the end of the string, the keys 355 + within the destination keyring will also be searched for signing keys. 356 + This allows for verification of certificate chains by adding each 357 + cert in order (starting closest to the root) to one keyring. 353 358 354 359 In all of these cases, if the signing key is found the signature of the key to 355 360 be linked will be verified using the signing key. The requested key is added
+25 -8
crypto/asymmetric_keys/asymmetric_type.c
··· 496 496 restrict_method = strsep(&next, ":"); 497 497 498 498 if ((strcmp(restrict_method, "key_or_keyring") == 0) && next) { 499 + char *key_text; 499 500 key_serial_t serial; 500 501 struct key *key; 502 + key_restrict_link_func_t link_fn = 503 + restrict_link_by_key_or_keyring; 504 + bool allow_null_key = false; 501 505 502 - if (kstrtos32(next, 0, &serial) < 0) 503 - goto out; 506 + key_text = strsep(&next, ":"); 504 507 505 - key = key_lookup(serial); 506 - if (IS_ERR(key)) { 507 - ret = ERR_CAST(key); 508 - goto out; 508 + if (next) { 509 + if (strcmp(next, "chain") != 0) 510 + goto out; 511 + 512 + link_fn = restrict_link_by_key_or_keyring_chain; 513 + allow_null_key = true; 509 514 } 510 515 511 - ret = asymmetric_restriction_alloc( 512 - restrict_link_by_key_or_keyring, key); 516 + if (kstrtos32(key_text, 0, &serial) < 0) 517 + goto out; 518 + 519 + if ((serial == 0) && allow_null_key) { 520 + key = NULL; 521 + } else { 522 + key = key_lookup(serial); 523 + if (IS_ERR(key)) { 524 + ret = ERR_CAST(key); 525 + goto out; 526 + } 527 + } 528 + 529 + ret = asymmetric_restriction_alloc(link_fn, key); 513 530 if (IS_ERR(ret)) 514 531 key_put(key); 515 532 }
+127 -45
crypto/asymmetric_keys/restrict.c
··· 109 109 return ret; 110 110 } 111 111 112 + static bool match_either_id(const struct asymmetric_key_ids *pair, 113 + const struct asymmetric_key_id *single) 114 + { 115 + return (asymmetric_key_id_same(pair->id[0], single) || 116 + asymmetric_key_id_same(pair->id[1], single)); 117 + } 118 + 119 + static int key_or_keyring_common(struct key *dest_keyring, 120 + const struct key_type *type, 121 + const union key_payload *payload, 122 + struct key *trusted, bool check_dest) 123 + { 124 + const struct public_key_signature *sig; 125 + struct key *key = NULL; 126 + int ret; 127 + 128 + pr_devel("==>%s()\n", __func__); 129 + 130 + if (!dest_keyring) 131 + return -ENOKEY; 132 + else if (dest_keyring->type != &key_type_keyring) 133 + return -EOPNOTSUPP; 134 + 135 + if (!trusted && !check_dest) 136 + return -ENOKEY; 137 + 138 + if (type != &key_type_asymmetric) 139 + return -EOPNOTSUPP; 140 + 141 + sig = payload->data[asym_auth]; 142 + if (!sig->auth_ids[0] && !sig->auth_ids[1]) 143 + return -ENOKEY; 144 + 145 + if (trusted) { 146 + if (trusted->type == &key_type_keyring) { 147 + /* See if we have a key that signed this one. */ 148 + key = find_asymmetric_key(trusted, sig->auth_ids[0], 149 + sig->auth_ids[1], false); 150 + if (IS_ERR(key)) 151 + key = NULL; 152 + } else if (trusted->type == &key_type_asymmetric) { 153 + const struct asymmetric_key_ids *signer_ids; 154 + 155 + signer_ids = asymmetric_key_ids(trusted); 156 + 157 + /* 158 + * The auth_ids come from the candidate key (the 159 + * one that is being considered for addition to 160 + * dest_keyring) and identify the key that was 161 + * used to sign. 162 + * 163 + * The signer_ids are identifiers for the 164 + * signing key specified for dest_keyring. 165 + * 166 + * The first auth_id is the preferred id, and 167 + * the second is the fallback. If only one 168 + * auth_id is present, it may match against 169 + * either signer_id. If two auth_ids are 170 + * present, the first auth_id must match one 171 + * signer_id and the second auth_id must match 172 + * the second signer_id. 173 + */ 174 + if (!sig->auth_ids[0] || !sig->auth_ids[1]) { 175 + const struct asymmetric_key_id *auth_id; 176 + 177 + auth_id = sig->auth_ids[0] ?: sig->auth_ids[1]; 178 + if (match_either_id(signer_ids, auth_id)) 179 + key = __key_get(trusted); 180 + 181 + } else if (asymmetric_key_id_same(signer_ids->id[1], 182 + sig->auth_ids[1]) && 183 + match_either_id(signer_ids, 184 + sig->auth_ids[0])) { 185 + key = __key_get(trusted); 186 + } 187 + } else { 188 + return -EOPNOTSUPP; 189 + } 190 + } 191 + 192 + if (check_dest && !key) { 193 + /* See if the destination has a key that signed this one. */ 194 + key = find_asymmetric_key(dest_keyring, sig->auth_ids[0], 195 + sig->auth_ids[1], false); 196 + if (IS_ERR(key)) 197 + key = NULL; 198 + } 199 + 200 + if (!key) 201 + return -ENOKEY; 202 + 203 + ret = key_validate(key); 204 + if (ret == 0) 205 + ret = verify_signature(key, sig); 206 + 207 + key_put(key); 208 + return ret; 209 + } 210 + 112 211 /** 113 212 * restrict_link_by_key_or_keyring - Restrict additions to a ring of public 114 213 * keys using the restrict_key information stored in the ring. ··· 231 132 const union key_payload *payload, 232 133 struct key *trusted) 233 134 { 234 - const struct public_key_signature *sig; 235 - struct key *key; 236 - int ret; 135 + return key_or_keyring_common(dest_keyring, type, payload, trusted, 136 + false); 137 + } 237 138 238 - pr_devel("==>%s()\n", __func__); 239 - 240 - if (!dest_keyring) 241 - return -ENOKEY; 242 - else if (dest_keyring->type != &key_type_keyring) 243 - return -EOPNOTSUPP; 244 - 245 - if (!trusted) 246 - return -ENOKEY; 247 - 248 - if (type != &key_type_asymmetric) 249 - return -EOPNOTSUPP; 250 - 251 - sig = payload->data[asym_auth]; 252 - if (!sig->auth_ids[0] && !sig->auth_ids[1]) 253 - return -ENOKEY; 254 - 255 - if (trusted->type == &key_type_keyring) { 256 - /* See if we have a key that signed this one. */ 257 - key = find_asymmetric_key(trusted, sig->auth_ids[0], 258 - sig->auth_ids[1], false); 259 - if (IS_ERR(key)) 260 - return -ENOKEY; 261 - } else if (trusted->type == &key_type_asymmetric) { 262 - const struct asymmetric_key_ids *kids; 263 - 264 - kids = asymmetric_key_ids(trusted); 265 - 266 - if (!asymmetric_key_id_same(kids->id[1], sig->auth_ids[0])) 267 - return -ENOKEY; 268 - 269 - key = __key_get(trusted); 270 - } else { 271 - return -EOPNOTSUPP; 272 - } 273 - 274 - ret = key_validate(key); 275 - if (ret == 0) 276 - ret = verify_signature(key, sig); 277 - 278 - key_put(key); 279 - return ret; 139 + /** 140 + * restrict_link_by_key_or_keyring_chain - Restrict additions to a ring of 141 + * public keys using the restrict_key information stored in the ring. 142 + * @dest_keyring: Keyring being linked to. 143 + * @type: The type of key being added. 144 + * @payload: The payload of the new key. 145 + * @trusted: A key or ring of keys that can be used to vouch for the new cert. 146 + * 147 + * Check the new certificate only against the key or keys passed in the data 148 + * parameter. If one of those is the signing key and validates the new 149 + * certificate, then mark the new certificate as being ok to link. 150 + * 151 + * Returns 0 if the new certificate was accepted, -ENOKEY if we 152 + * couldn't find a matching parent certificate in the trusted list, 153 + * -EKEYREJECTED if the signature check fails, and some other error if 154 + * there is a matching certificate but the signature check cannot be 155 + * performed. 156 + */ 157 + int restrict_link_by_key_or_keyring_chain(struct key *dest_keyring, 158 + const struct key_type *type, 159 + const union key_payload *payload, 160 + struct key *trusted) 161 + { 162 + return key_or_keyring_common(dest_keyring, type, payload, trusted, 163 + true); 280 164 }
+5
include/crypto/public_key.h
··· 60 60 const union key_payload *payload, 61 61 struct key *trusted); 62 62 63 + extern int restrict_link_by_key_or_keyring_chain(struct key *trust_keyring, 64 + const struct key_type *type, 65 + const union key_payload *payload, 66 + struct key *trusted); 67 + 63 68 extern int verify_signature(const struct key *key, 64 69 const struct public_key_signature *sig); 65 70