From 8f35069f76d1cbd9fa83d80b0a80a431ee6e7db3 Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Tue, 30 Aug 2016 11:33:13 -0700 Subject: KEYS: Split role of the keyring pointer for keyring restrict functions The first argument to the restrict_link_func_t functions was a keyring pointer. These functions are called by the key subsystem with this argument set to the destination keyring, but restrict_link_by_signature expects a pointer to the relevant trusted keyring. Restrict functions may need something other than a single struct key pointer to allow or reject key linkage, so the data used to make that decision (such as the trust keyring) is moved to a new, fourth argument. The first argument is now always the destination keyring. Signed-off-by: Mat Martineau --- crypto/asymmetric_keys/restrict.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/crypto/asymmetric_keys/restrict.c b/crypto/asymmetric_keys/restrict.c index 19d1afb9..a3afbf78 100644 --- a/crypto/asymmetric_keys/restrict.c +++ b/crypto/asymmetric_keys/restrict.c @@ -56,9 +56,10 @@ __setup("ca_keys=", ca_keys_setup); /** * restrict_link_by_signature - Restrict additions to a ring of public keys - * @trust_keyring: A ring of keys that can be used to vouch for the new cert. + * @dest_keyring: Keyring being linked to. * @type: The type of key being added. * @payload: The payload of the new key. + * @trust_keyring: A ring of keys that can be used to vouch for the new cert. * * Check the new certificate against the ones in the trust keyring. If one of * those is the signing key and validates the new certificate, then mark the @@ -69,9 +70,10 @@ __setup("ca_keys=", ca_keys_setup); * signature check fails or the key is blacklisted and some other error if * there is a matching certificate but the signature check cannot be performed. */ -int restrict_link_by_signature(struct key *trust_keyring, +int restrict_link_by_signature(struct key *dest_keyring, const struct key_type *type, - const union key_payload *payload) + const union key_payload *payload, + struct key *trust_keyring) { const struct public_key_signature *sig; struct key *key; -- cgit v1.2.3 From 19b15e919c65d5d76076c251c89d34d1227c6512 Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Fri, 6 May 2016 14:25:39 -0700 Subject: KEYS: Add a lookup_restriction function for the asymmetric key type Look up asymmetric keyring restriction information using the key-type lookup_restrict hook. Signed-off-by: Mat Martineau --- crypto/asymmetric_keys/asymmetric_type.c | 52 +++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 8 deletions(-) diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c index 6600181d..2e3380d0 100644 --- a/crypto/asymmetric_keys/asymmetric_type.c +++ b/crypto/asymmetric_keys/asymmetric_type.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "asymmetric_keys.h" MODULE_LICENSE("GPL"); @@ -451,15 +452,50 @@ static void asymmetric_key_destroy(struct key *key) asymmetric_key_free_kids(kids); } +static struct key_restriction *asymmetric_restriction_alloc( + key_restrict_link_func_t check, + struct key *key) +{ + struct key_restriction *keyres = + kzalloc(sizeof(struct key_restriction), GFP_KERNEL); + + if (!keyres) + return ERR_PTR(-ENOMEM); + + keyres->check = check; + keyres->key = key; + keyres->keytype = &key_type_asymmetric; + + return keyres; +} + +/* + * look up keyring restrict functions for asymmetric keys + */ +static struct key_restriction *asymmetric_lookup_restriction( + const char *restriction) +{ + if (strcmp("builtin_trusted", restriction) == 0) + return asymmetric_restriction_alloc( + restrict_link_by_builtin_trusted, NULL); + + if (strcmp("builtin_and_secondary_trusted", restriction) == 0) + return asymmetric_restriction_alloc( + restrict_link_by_builtin_and_secondary_trusted, NULL); + + return ERR_PTR(-EINVAL); +} + struct key_type key_type_asymmetric = { - .name = "asymmetric", - .preparse = asymmetric_key_preparse, - .free_preparse = asymmetric_key_free_preparse, - .instantiate = generic_key_instantiate, - .match_preparse = asymmetric_key_match_preparse, - .match_free = asymmetric_key_match_free, - .destroy = asymmetric_key_destroy, - .describe = asymmetric_key_describe, + .name = "asymmetric", + .preparse = asymmetric_key_preparse, + .free_preparse = asymmetric_key_free_preparse, + .instantiate = generic_key_instantiate, + .match_preparse = asymmetric_key_match_preparse, + .match_free = asymmetric_key_match_free, + .destroy = asymmetric_key_destroy, + .describe = asymmetric_key_describe, + .lookup_restriction = asymmetric_lookup_restriction, }; EXPORT_SYMBOL_GPL(key_type_asymmetric); -- cgit v1.2.3 From 53b7a22cac5cf5144c1300bc033c23cf47930cf7 Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Mon, 27 Jun 2016 16:45:16 -0700 Subject: KEYS: Restrict asymmetric key linkage using a specific keychain Adds restrict_link_by_signature_keyring(), which uses the restrict_key member of the provided destination_keyring data structure as the key or keyring to search for signing keys. Signed-off-by: Mat Martineau --- crypto/asymmetric_keys/asymmetric_type.c | 35 +++++++++++++++- crypto/asymmetric_keys/restrict.c | 71 ++++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 1 deletion(-) diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c index 2e3380d0..72700ed8 100644 --- a/crypto/asymmetric_keys/asymmetric_type.c +++ b/crypto/asymmetric_keys/asymmetric_type.c @@ -475,6 +475,11 @@ static struct key_restriction *asymmetric_restriction_alloc( static struct key_restriction *asymmetric_lookup_restriction( const char *restriction) { + char *restrict_method; + char *parse_buf; + char *next; + struct key_restriction *ret = ERR_PTR(-EINVAL); + if (strcmp("builtin_trusted", restriction) == 0) return asymmetric_restriction_alloc( restrict_link_by_builtin_trusted, NULL); @@ -483,7 +488,35 @@ static struct key_restriction *asymmetric_lookup_restriction( return asymmetric_restriction_alloc( restrict_link_by_builtin_and_secondary_trusted, NULL); - return ERR_PTR(-EINVAL); + parse_buf = kstrndup(restriction, PAGE_SIZE, GFP_KERNEL); + if (!parse_buf) + return ERR_PTR(-ENOMEM); + + next = parse_buf; + restrict_method = strsep(&next, ":"); + + if ((strcmp(restrict_method, "key_or_keyring") == 0) && next) { + key_serial_t serial; + struct key *key; + + if (kstrtos32(next, 0, &serial) < 0) + goto out; + + key = key_lookup(serial); + if (IS_ERR(key)) { + ret = ERR_CAST(key); + goto out; + } + + ret = asymmetric_restriction_alloc( + restrict_link_by_key_or_keyring, key); + if (IS_ERR(ret)) + key_put(key); + } + +out: + kfree(parse_buf); + return ret; } struct key_type key_type_asymmetric = { diff --git a/crypto/asymmetric_keys/restrict.c b/crypto/asymmetric_keys/restrict.c index a3afbf78..183cb642 100644 --- a/crypto/asymmetric_keys/restrict.c +++ b/crypto/asymmetric_keys/restrict.c @@ -108,3 +108,74 @@ int restrict_link_by_signature(struct key *dest_keyring, key_put(key); return ret; } + +/** + * restrict_link_by_key_or_keyring - Restrict additions to a ring of public + * keys using the restrict_key information stored in the ring. + * @dest_keyring: Keyring being linked to. + * @type: The type of key being added. + * @payload: The payload of the new key. + * @trusted: A key or ring of keys that can be used to vouch for the new cert. + * + * Check the new certificate only against the key or keys passed in the data + * parameter. If one of those is the signing key and validates the new + * certificate, then mark the new certificate as being ok to link. + * + * Returns 0 if the new certificate was accepted, -ENOKEY if we + * couldn't find a matching parent certificate in the trusted list, + * -EKEYREJECTED if the signature check fails, and some other error if + * there is a matching certificate but the signature check cannot be + * performed. + */ +int restrict_link_by_key_or_keyring(struct key *dest_keyring, + const struct key_type *type, + const union key_payload *payload, + struct key *trusted) +{ + const struct public_key_signature *sig; + struct key *key; + int ret; + + pr_devel("==>%s()\n", __func__); + + if (!dest_keyring) + return -ENOKEY; + else if (dest_keyring->type != &key_type_keyring) + return -EOPNOTSUPP; + + if (!trusted) + return -ENOKEY; + + if (type != &key_type_asymmetric) + return -EOPNOTSUPP; + + sig = payload->data[asym_auth]; + if (!sig->auth_ids[0] && !sig->auth_ids[1]) + return -ENOKEY; + + if (trusted->type == &key_type_keyring) { + /* See if we have a key that signed this one. */ + key = find_asymmetric_key(trusted, sig->auth_ids[0], + sig->auth_ids[1], false); + if (IS_ERR(key)) + return -ENOKEY; + } else if (trusted->type == &key_type_asymmetric) { + const struct asymmetric_key_ids *kids; + + kids = asymmetric_key_ids(trusted); + + if (!asymmetric_key_id_same(kids->id[1], sig->auth_ids[0])) + return -ENOKEY; + + key = __key_get(trusted); + } else { + return -EOPNOTSUPP; + } + + ret = key_validate(key); + if (ret == 0) + ret = verify_signature(key, sig); + + key_put(key); + return ret; +} -- cgit v1.2.3 From c6abad0244ad8f5f9829e74fc9341d3e904be287 Mon Sep 17 00:00:00 2001 From: Mat Martineau Date: Tue, 4 Oct 2016 16:42:45 -0700 Subject: 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::chain"); Signed-off-by: Mat Martineau --- crypto/asymmetric_keys/asymmetric_type.c | 31 ++++-- crypto/asymmetric_keys/restrict.c | 158 +++++++++++++++++++++++-------- 2 files changed, 144 insertions(+), 45 deletions(-) diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c index 72700ed8..e4b0ed38 100644 --- a/crypto/asymmetric_keys/asymmetric_type.c +++ b/crypto/asymmetric_keys/asymmetric_type.c @@ -496,20 +496,37 @@ static struct key_restriction *asymmetric_lookup_restriction( restrict_method = strsep(&next, ":"); if ((strcmp(restrict_method, "key_or_keyring") == 0) && next) { + char *key_text; key_serial_t serial; struct key *key; + key_restrict_link_func_t link_fn = + restrict_link_by_key_or_keyring; + bool allow_null_key = false; - if (kstrtos32(next, 0, &serial) < 0) - goto out; + key_text = strsep(&next, ":"); + + if (next) { + if (strcmp(next, "chain") != 0) + goto out; + + link_fn = restrict_link_by_key_or_keyring_chain; + allow_null_key = true; + } - key = key_lookup(serial); - if (IS_ERR(key)) { - ret = ERR_CAST(key); + if (kstrtos32(key_text, 0, &serial) < 0) goto out; + + if ((serial == 0) && allow_null_key) { + key = NULL; + } else { + key = key_lookup(serial); + if (IS_ERR(key)) { + ret = ERR_CAST(key); + goto out; + } } - ret = asymmetric_restriction_alloc( - restrict_link_by_key_or_keyring, key); + ret = asymmetric_restriction_alloc(link_fn, key); if (IS_ERR(ret)) key_put(key); } diff --git a/crypto/asymmetric_keys/restrict.c b/crypto/asymmetric_keys/restrict.c index 183cb642..86fb6850 100644 --- a/crypto/asymmetric_keys/restrict.c +++ b/crypto/asymmetric_keys/restrict.c @@ -109,31 +109,20 @@ int restrict_link_by_signature(struct key *dest_keyring, return ret; } -/** - * restrict_link_by_key_or_keyring - Restrict additions to a ring of public - * keys using the restrict_key information stored in the ring. - * @dest_keyring: Keyring being linked to. - * @type: The type of key being added. - * @payload: The payload of the new key. - * @trusted: A key or ring of keys that can be used to vouch for the new cert. - * - * Check the new certificate only against the key or keys passed in the data - * parameter. If one of those is the signing key and validates the new - * certificate, then mark the new certificate as being ok to link. - * - * Returns 0 if the new certificate was accepted, -ENOKEY if we - * couldn't find a matching parent certificate in the trusted list, - * -EKEYREJECTED if the signature check fails, and some other error if - * there is a matching certificate but the signature check cannot be - * performed. - */ -int restrict_link_by_key_or_keyring(struct key *dest_keyring, - const struct key_type *type, - const union key_payload *payload, - struct key *trusted) +static bool match_either_id(const struct asymmetric_key_ids *pair, + const struct asymmetric_key_id *single) +{ + return (asymmetric_key_id_same(pair->id[0], single) || + asymmetric_key_id_same(pair->id[1], single)); +} + +static int key_or_keyring_common(struct key *dest_keyring, + const struct key_type *type, + const union key_payload *payload, + struct key *trusted, bool check_dest) { const struct public_key_signature *sig; - struct key *key; + struct key *key = NULL; int ret; pr_devel("==>%s()\n", __func__); @@ -143,7 +132,7 @@ int restrict_link_by_key_or_keyring(struct key *dest_keyring, else if (dest_keyring->type != &key_type_keyring) return -EOPNOTSUPP; - if (!trusted) + if (!trusted && !check_dest) return -ENOKEY; if (type != &key_type_asymmetric) @@ -153,25 +142,64 @@ int restrict_link_by_key_or_keyring(struct key *dest_keyring, if (!sig->auth_ids[0] && !sig->auth_ids[1]) return -ENOKEY; - if (trusted->type == &key_type_keyring) { - /* See if we have a key that signed this one. */ - key = find_asymmetric_key(trusted, sig->auth_ids[0], - sig->auth_ids[1], false); - if (IS_ERR(key)) - return -ENOKEY; - } else if (trusted->type == &key_type_asymmetric) { - const struct asymmetric_key_ids *kids; + if (trusted) { + if (trusted->type == &key_type_keyring) { + /* See if we have a key that signed this one. */ + key = find_asymmetric_key(trusted, sig->auth_ids[0], + sig->auth_ids[1], false); + if (IS_ERR(key)) + key = NULL; + } else if (trusted->type == &key_type_asymmetric) { + const struct asymmetric_key_ids *signer_ids; - kids = asymmetric_key_ids(trusted); + signer_ids = asymmetric_key_ids(trusted); - if (!asymmetric_key_id_same(kids->id[1], sig->auth_ids[0])) - return -ENOKEY; + /* + * The auth_ids come from the candidate key (the + * one that is being considered for addition to + * dest_keyring) and identify the key that was + * used to sign. + * + * The signer_ids are identifiers for the + * signing key specified for dest_keyring. + * + * The first auth_id is the preferred id, and + * the second is the fallback. If only one + * auth_id is present, it may match against + * either signer_id. If two auth_ids are + * present, the first auth_id must match one + * signer_id and the second auth_id must match + * the second signer_id. + */ + if (!sig->auth_ids[0] || !sig->auth_ids[1]) { + const struct asymmetric_key_id *auth_id; - key = __key_get(trusted); - } else { - return -EOPNOTSUPP; + auth_id = sig->auth_ids[0] ?: sig->auth_ids[1]; + if (match_either_id(signer_ids, auth_id)) + key = __key_get(trusted); + + } else if (asymmetric_key_id_same(signer_ids->id[1], + sig->auth_ids[1]) && + match_either_id(signer_ids, + sig->auth_ids[0])) { + key = __key_get(trusted); + } + } else { + return -EOPNOTSUPP; + } } + if (check_dest && !key) { + /* See if the destination has a key that signed this one. */ + key = find_asymmetric_key(dest_keyring, sig->auth_ids[0], + sig->auth_ids[1], false); + if (IS_ERR(key)) + key = NULL; + } + + if (!key) + return -ENOKEY; + ret = key_validate(key); if (ret == 0) ret = verify_signature(key, sig); @@ -179,3 +207,57 @@ int restrict_link_by_key_or_keyring(struct key *dest_keyring, key_put(key); return ret; } + +/** + * restrict_link_by_key_or_keyring - Restrict additions to a ring of public + * keys using the restrict_key information stored in the ring. + * @dest_keyring: Keyring being linked to. + * @type: The type of key being added. + * @payload: The payload of the new key. + * @trusted: A key or ring of keys that can be used to vouch for the new cert. + * + * Check the new certificate only against the key or keys passed in the data + * parameter. If one of those is the signing key and validates the new + * certificate, then mark the new certificate as being ok to link. + * + * Returns 0 if the new certificate was accepted, -ENOKEY if we + * couldn't find a matching parent certificate in the trusted list, + * -EKEYREJECTED if the signature check fails, and some other error if + * there is a matching certificate but the signature check cannot be + * performed. + */ +int restrict_link_by_key_or_keyring(struct key *dest_keyring, + const struct key_type *type, + const union key_payload *payload, + struct key *trusted) +{ + return key_or_keyring_common(dest_keyring, type, payload, trusted, + false); +} + +/** + * restrict_link_by_key_or_keyring_chain - Restrict additions to a ring of + * public keys using the restrict_key information stored in the ring. + * @dest_keyring: Keyring being linked to. + * @type: The type of key being added. + * @payload: The payload of the new key. + * @trusted: A key or ring of keys that can be used to vouch for the new cert. + * + * Check the new certificate only against the key or keys passed in the data + * parameter. If one of those is the signing key and validates the new + * certificate, then mark the new certificate as being ok to link. + * + * Returns 0 if the new certificate was accepted, -ENOKEY if we + * couldn't find a matching parent certificate in the trusted list, + * -EKEYREJECTED if the signature check fails, and some other error if + * there is a matching certificate but the signature check cannot be + * performed. + */ +int restrict_link_by_key_or_keyring_chain(struct key *dest_keyring, + const struct key_type *type, + const union key_payload *payload, + struct key *trusted) +{ + return key_or_keyring_common(dest_keyring, type, payload, trusted, + true); +} -- cgit v1.2.3