Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f1b731db authored by Dmitry Kasatkin's avatar Dmitry Kasatkin Committed by David Howells
Browse files

KEYS: Restore partial ID matching functionality for asymmetric keys



Bring back the functionality whereby an asymmetric key can be matched with a
partial match on one of its IDs.

Whilst we're at it, allow for the possibility of having an increased number of
IDs.

Reported-by: default avatarDmitry Kasatkin <d.kasatkin@samsung.com>
Signed-off-by: default avatarDmitry Kasatkin <d.kasatkin@samsung.com>
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
parent dd2f6c44
Loading
Loading
Loading
Loading
+0 −3
Original line number Diff line number Diff line
@@ -9,9 +9,6 @@
 * 2 of the Licence, or (at your option) any later version.
 */

extern bool asymmetric_match_key_ids(const struct asymmetric_key_ids *kids,
				     const struct asymmetric_key_id *match_id);

extern struct asymmetric_key_id *asymmetric_key_hex_to_key_id(const char *id);

static inline
+57 −13
Original line number Diff line number Diff line
@@ -65,23 +65,44 @@ bool asymmetric_key_id_same(const struct asymmetric_key_id *kid1,
}
EXPORT_SYMBOL_GPL(asymmetric_key_id_same);

/**
 * asymmetric_key_id_partial - Return true if two asymmetric keys IDs
 * partially match
 * @kid_1, @kid_2: The key IDs to compare
 */
bool asymmetric_key_id_partial(const struct asymmetric_key_id *kid1,
			       const struct asymmetric_key_id *kid2)
{
	if (!kid1 || !kid2)
		return false;
	if (kid1->len < kid2->len)
		return false;
	return memcmp(kid1->data + (kid1->len - kid2->len),
		      kid2->data, kid2->len) == 0;
}
EXPORT_SYMBOL_GPL(asymmetric_key_id_partial);

/**
 * asymmetric_match_key_ids - Search asymmetric key IDs
 * @kids: The list of key IDs to check
 * @match_id: The key ID we're looking for
 * @match: The match function to use
 */
bool asymmetric_match_key_ids(const struct asymmetric_key_ids *kids,
			      const struct asymmetric_key_id *match_id)
static bool asymmetric_match_key_ids(
	const struct asymmetric_key_ids *kids,
	const struct asymmetric_key_id *match_id,
	bool (*match)(const struct asymmetric_key_id *kid1,
		      const struct asymmetric_key_id *kid2))
{
	int i;

	if (!kids || !match_id)
		return false;
	if (asymmetric_key_id_same(kids->id[0], match_id))
		return true;
	if (asymmetric_key_id_same(kids->id[1], match_id))
	for (i = 0; i < ARRAY_SIZE(kids->id); i++)
		if (match(kids->id[i], match_id))
			return true;
	return false;
}
EXPORT_SYMBOL_GPL(asymmetric_match_key_ids);

/**
 * asymmetric_key_hex_to_key_id - Convert a hex string into a key ID.
@@ -113,7 +134,7 @@ struct asymmetric_key_id *asymmetric_key_hex_to_key_id(const char *id)
}

/*
 * Match asymmetric keys by ID.
 * Match asymmetric keys by an exact match on an ID.
 */
static bool asymmetric_key_cmp(const struct key *key,
			       const struct key_match_data *match_data)
@@ -121,7 +142,21 @@ static bool asymmetric_key_cmp(const struct key *key,
	const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
	const struct asymmetric_key_id *match_id = match_data->preparsed;

	return asymmetric_match_key_ids(kids, match_id);
	return asymmetric_match_key_ids(kids, match_id,
					asymmetric_key_id_same);
}

/*
 * Match asymmetric keys by a partial match on an IDs.
 */
static bool asymmetric_key_cmp_partial(const struct key *key,
				       const struct key_match_data *match_data)
{
	const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
	const struct asymmetric_key_id *match_id = match_data->preparsed;

	return asymmetric_match_key_ids(kids, match_id,
					asymmetric_key_id_partial);
}

/*
@@ -131,7 +166,8 @@ static bool asymmetric_key_cmp(const struct key *key,
 * There are some specifiers for matching key IDs rather than by the key
 * description:
 *
 *	"id:<id>" - request a key by any available ID
 *	"id:<id>" - find a key by partial match on any available ID
 *	"ex:<id>" - find a key by exact match on any available ID
 *
 * These have to be searched by iteration rather than by direct lookup because
 * the key is hashed according to its description.
@@ -141,6 +177,8 @@ static int asymmetric_key_match_preparse(struct key_match_data *match_data)
	struct asymmetric_key_id *match_id;
	const char *spec = match_data->raw_data;
	const char *id;
	bool (*cmp)(const struct key *, const struct key_match_data *) =
		asymmetric_key_cmp;

	if (!spec || !*spec)
		return -EINVAL;
@@ -148,6 +186,11 @@ static int asymmetric_key_match_preparse(struct key_match_data *match_data)
	    spec[1] == 'd' &&
	    spec[2] == ':') {
		id = spec + 3;
		cmp = asymmetric_key_cmp_partial;
	} else if (spec[0] == 'e' &&
		   spec[1] == 'x' &&
		   spec[2] == ':') {
		id = spec + 3;
	} else {
		goto default_match;
	}
@@ -157,7 +200,7 @@ static int asymmetric_key_match_preparse(struct key_match_data *match_data)
		return PTR_ERR(match_id);

	match_data->preparsed = match_id;
	match_data->cmp = asymmetric_key_cmp;
	match_data->cmp = cmp;
	match_data->lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE;
	return 0;

@@ -251,6 +294,7 @@ static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
{
	struct asymmetric_key_subtype *subtype = prep->type_data[0];
	struct asymmetric_key_ids *kids = prep->type_data[1];
	int i;

	pr_devel("==>%s()\n", __func__);

@@ -259,8 +303,8 @@ static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
		module_put(subtype->owner);
	}
	if (kids) {
		kfree(kids->id[0]);
		kfree(kids->id[1]);
		for (i = 0; i < ARRAY_SIZE(kids->id); i++)
			kfree(kids->id[i]);
		kfree(kids);
	}
	kfree(prep->description);
+6 −3
Original line number Diff line number Diff line
@@ -54,7 +54,8 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
		/* Look to see if this certificate is present in the trusted
		 * keys.
		 */
		key = x509_request_asymmetric_key(trust_keyring, x509->id);
		key = x509_request_asymmetric_key(trust_keyring, x509->id,
						  false);
		if (!IS_ERR(key)) {
			/* One of the X.509 certificates in the PKCS#7 message
			 * is apparently the same as one we already trust.
@@ -85,7 +86,8 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
	 * trusted keys.
	 */
	if (last && last->authority) {
		key = x509_request_asymmetric_key(trust_keyring, last->authority);
		key = x509_request_asymmetric_key(trust_keyring, last->authority,
						  false);
		if (!IS_ERR(key)) {
			x509 = last;
			pr_devel("sinfo %u: Root cert %u signer is key %x\n",
@@ -100,7 +102,8 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
	 * the signed info directly.
	 */
	key = x509_request_asymmetric_key(trust_keyring,
					  sinfo->signing_cert_id);
					  sinfo->signing_cert_id,
					  false);
	if (!IS_ERR(key)) {
		pr_devel("sinfo %u: Direct signer is key %x\n",
			 sinfo->index, key_serial(key));
+13 −5
Original line number Diff line number Diff line
@@ -53,13 +53,15 @@ __setup("ca_keys=", ca_keys_setup);
 * x509_request_asymmetric_key - Request a key by X.509 certificate params.
 * @keyring: The keys to search.
 * @kid: The key ID.
 * @partial: Use partial match if true, exact if false.
 *
 * Find a key in the given keyring by subject name and key ID.  These might,
 * for instance, be the issuer name and the authority key ID of an X.509
 * certificate that needs to be verified.
 */
struct key *x509_request_asymmetric_key(struct key *keyring,
					const struct asymmetric_key_id *kid)
					const struct asymmetric_key_id *kid,
					bool partial)
{
	key_ref_t key;
	char *id, *p;
@@ -69,8 +71,13 @@ struct key *x509_request_asymmetric_key(struct key *keyring,
	if (!id)
		return ERR_PTR(-ENOMEM);

	if (partial) {
		*p++ = 'i';
		*p++ = 'd';
	} else {
		*p++ = 'e';
		*p++ = 'x';
	}
	*p++ = ':';
	p = bin2hex(p, kid->data, kid->len);
	*p = 0;
@@ -207,10 +214,11 @@ static int x509_validate_trust(struct x509_certificate *cert,
	if (!trust_keyring)
		return -EOPNOTSUPP;

	if (ca_keyid && !asymmetric_key_id_same(cert->authority, ca_keyid))
	if (ca_keyid && !asymmetric_key_id_partial(cert->authority, ca_keyid))
		return -EPERM;

	key = x509_request_asymmetric_key(trust_keyring, cert->authority);
	key = x509_request_asymmetric_key(trust_keyring, cert->authority,
					  false);
	if (!IS_ERR(key))  {
		if (!use_builtin_keys
		    || test_bit(KEY_FLAG_BUILTIN, &key->flags))
+2 −1
Original line number Diff line number Diff line
@@ -101,6 +101,7 @@ extern int verify_signature(const struct key *key,

struct asymmetric_key_id;
extern struct key *x509_request_asymmetric_key(struct key *keyring,
					       const struct asymmetric_key_id *kid);
					       const struct asymmetric_key_id *kid,
					       bool partial);

#endif /* _LINUX_PUBLIC_KEY_H */
Loading