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__);
        else if (dest_keyring->type != &key_type_keyring)
                return -EOPNOTSUPP;
 
-       if (!trusted)
+       if (!trusted && !check_dest)
                return -ENOKEY;
 
        if (type != &key_type_asymmetric)
        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);
        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);
+}