summaryrefslogtreecommitdiff
path: root/crypto/asymmetric_keys/restrict.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/asymmetric_keys/restrict.c')
-rw-r--r--crypto/asymmetric_keys/restrict.c161
1 files changed, 158 insertions, 3 deletions
diff --git a/crypto/asymmetric_keys/restrict.c b/crypto/asymmetric_keys/restrict.c
index 19d1afb9890f..86fb68508952 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;
@@ -106,3 +108,156 @@ int restrict_link_by_signature(struct key *trust_keyring,
key_put(key);
return ret;
}
+
+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 = NULL;
+ int ret;
+
+ pr_devel("==>%s()\n", __func__);
+
+ if (!dest_keyring)
+ return -ENOKEY;
+ else if (dest_keyring->type != &key_type_keyring)
+ return -EOPNOTSUPP;
+
+ if (!trusted && !check_dest)
+ 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) {
+ 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;
+
+ signer_ids = asymmetric_key_ids(trusted);
+
+ /*
+ * 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;
+
+ 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);
+}