|
@@ -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);
|
|
|
+}
|