Commit dabd40ec authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'tpmdd-next-v5.17-fixed' of...

Merge tag 'tpmdd-next-v5.17-fixed' of git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd

Pull TPM updates from Jarkko Sakkinen:
 "Other than bug fixes for TPM, this includes a patch for asymmetric
  keys to allow to look up and verify with self-signed certificates
  (keys without so called AKID - Authority Key Identifier) using a new
  "dn:" prefix in the query"

* tag 'tpmdd-next-v5.17-fixed' of git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd:
  lib: remove redundant assignment to variable ret
  tpm: fix NPE on probe for missing device
  tpm: fix potential NULL pointer access in tpm_del_char_device
  tpm: Add Upgrade/Reduced mode support for TPM2 modules
  char: tpm: cr50: Set TPM_FIRMWARE_POWER_MANAGED based on device property
  keys: X.509 public key issuer lookup without AKID
  tpm_tis: Fix an error handling path in 'tpm_tis_core_init()'
  tpm: tpm_tis_spi_cr50: Add default RNG quality
  tpm/st33zp24: drop unneeded over-commenting
  tpm: add request_locality before write TPM_INT_ENABLE
parents 4aa1b825 d99a8af4
Loading
Loading
Loading
Loading
+44 −13
Original line number Diff line number Diff line
@@ -36,16 +36,23 @@ static DECLARE_RWSEM(asymmetric_key_parsers_sem);
 * find_asymmetric_key - Find a key by ID.
 * @keyring: The keys to search.
 * @id_0: The first ID to look for or NULL.
 * @id_1: The second ID to look for or NULL.
 * @partial: Use partial match if true, exact if false.
 * @id_1: The second ID to look for or NULL, matched together with @id_0
 * against @keyring keys' id[0] and id[1].
 * @id_2: The fallback ID to match against @keyring keys' id[2] if both of the
 * other IDs are NULL.
 * @partial: Use partial match for @id_0 and @id_1 if true, exact if false.
 *
 * Find a key in the given keyring by identifier.  The preferred identifier is
 * the id_0 and the fallback identifier is the id_1.  If both are given, the
 * lookup is by the former, but the latter must also match.
 * former is matched (exactly or partially) against either of the sought key's
 * identifiers and the latter must match the found key's second identifier
 * exactly.  If both are missing, id_2 must match the sought key's third
 * identifier exactly.
 */
struct key *find_asymmetric_key(struct key *keyring,
				const struct asymmetric_key_id *id_0,
				const struct asymmetric_key_id *id_1,
				const struct asymmetric_key_id *id_2,
				bool partial)
{
	struct key *key;
@@ -54,14 +61,17 @@ struct key *find_asymmetric_key(struct key *keyring,
	char *req, *p;
	int len;

	BUG_ON(!id_0 && !id_1);
	WARN_ON(!id_0 && !id_1 && !id_2);

	if (id_0) {
		lookup = id_0->data;
		len = id_0->len;
	} else {
	} else if (id_1) {
		lookup = id_1->data;
		len = id_1->len;
	} else {
		lookup = id_2->data;
		len = id_2->len;
	}

	/* Construct an identifier "id:<keyid>". */
@@ -69,7 +79,10 @@ struct key *find_asymmetric_key(struct key *keyring,
	if (!req)
		return ERR_PTR(-ENOMEM);

	if (partial) {
	if (!id_0 && !id_1) {
		*p++ = 'd';
		*p++ = 'n';
	} else if (partial) {
		*p++ = 'i';
		*p++ = 'd';
	} else {
@@ -185,8 +198,8 @@ bool asymmetric_key_id_partial(const struct asymmetric_key_id *kid1,
EXPORT_SYMBOL_GPL(asymmetric_key_id_partial);

/**
 * asymmetric_match_key_ids - Search asymmetric key IDs
 * @kids: The list of key IDs to check
 * asymmetric_match_key_ids - Search asymmetric key IDs 1 & 2
 * @kids: The pair of key IDs to check
 * @match_id: The key ID we're looking for
 * @match: The match function to use
 */
@@ -200,7 +213,7 @@ static bool asymmetric_match_key_ids(

	if (!kids || !match_id)
		return false;
	for (i = 0; i < ARRAY_SIZE(kids->id); i++)
	for (i = 0; i < 2; i++)
		if (match(kids->id[i], match_id))
			return true;
	return false;
@@ -244,7 +257,7 @@ struct asymmetric_key_id *asymmetric_key_hex_to_key_id(const char *id)
}

/*
 * Match asymmetric keys by an exact match on an ID.
 * Match asymmetric keys by an exact match on one of the first two IDs.
 */
static bool asymmetric_key_cmp(const struct key *key,
			       const struct key_match_data *match_data)
@@ -257,7 +270,7 @@ static bool asymmetric_key_cmp(const struct key *key,
}

/*
 * Match asymmetric keys by a partial match on an IDs.
 * Match asymmetric keys by a partial match on one of the first two IDs.
 */
static bool asymmetric_key_cmp_partial(const struct key *key,
				       const struct key_match_data *match_data)
@@ -269,6 +282,18 @@ static bool asymmetric_key_cmp_partial(const struct key *key,
					asymmetric_key_id_partial);
}

/*
 * Match asymmetric keys by an exact match on the third IDs.
 */
static bool asymmetric_key_cmp_name(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 kids && asymmetric_key_id_same(kids->id[2], match_id);
}

/*
 * Preparse the match criterion.  If we don't set lookup_type and cmp,
 * the default will be an exact match on the key description.
@@ -276,8 +301,9 @@ static bool asymmetric_key_cmp_partial(const struct key *key,
 * There are some specifiers for matching key IDs rather than by the key
 * description:
 *
 *	"id:<id>" - find a key by partial match on any available ID
 *	"ex:<id>" - find a key by exact match on any available ID
 *	"id:<id>" - find a key by partial match on one of the first two IDs
 *	"ex:<id>" - find a key by exact match on one of the first two IDs
 *	"dn:<id>" - find a key by exact match on the third ID
 *
 * These have to be searched by iteration rather than by direct lookup because
 * the key is hashed according to its description.
@@ -301,6 +327,11 @@ static int asymmetric_key_match_preparse(struct key_match_data *match_data)
		   spec[1] == 'x' &&
		   spec[2] == ':') {
		id = spec + 3;
	} else if (spec[0] == 'd' &&
		   spec[1] == 'n' &&
		   spec[2] == ':') {
		id = spec + 3;
		cmp = asymmetric_key_cmp_name;
	} else {
		goto default_match;
	}
+3 −3
Original line number Diff line number Diff line
@@ -48,7 +48,7 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
		 * keys.
		 */
		key = find_asymmetric_key(trust_keyring,
					  x509->id, x509->skid, false);
					  x509->id, x509->skid, NULL, 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.
@@ -82,7 +82,7 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
		key = find_asymmetric_key(trust_keyring,
					  last->sig->auth_ids[0],
					  last->sig->auth_ids[1],
					  false);
					  NULL, false);
		if (!IS_ERR(key)) {
			x509 = last;
			pr_devel("sinfo %u: Root cert %u signer is key %x\n",
@@ -97,7 +97,7 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
	 * the signed info directly.
	 */
	key = find_asymmetric_key(trust_keyring,
				  sinfo->sig->auth_ids[0], NULL, false);
				  sinfo->sig->auth_ids[0], NULL, NULL, false);
	if (!IS_ERR(key)) {
		pr_devel("sinfo %u: Direct signer is key %x\n",
			 sinfo->index, key_serial(key));
+29 −19
Original line number Diff line number Diff line
@@ -87,7 +87,7 @@ int restrict_link_by_signature(struct key *dest_keyring,
	sig = payload->data[asym_auth];
	if (!sig)
		return -ENOPKG;
	if (!sig->auth_ids[0] && !sig->auth_ids[1])
	if (!sig->auth_ids[0] && !sig->auth_ids[1] && !sig->auth_ids[2])
		return -ENOKEY;

	if (ca_keyid && !asymmetric_key_id_partial(sig->auth_ids[1], ca_keyid))
@@ -96,7 +96,7 @@ int restrict_link_by_signature(struct key *dest_keyring,
	/* See if we have a key that signed this one. */
	key = find_asymmetric_key(trust_keyring,
				  sig->auth_ids[0], sig->auth_ids[1],
				  false);
				  sig->auth_ids[2], false);
	if (IS_ERR(key))
		return -ENOKEY;

@@ -108,11 +108,11 @@ int restrict_link_by_signature(struct key *dest_keyring,
	return ret;
}

static bool match_either_id(const struct asymmetric_key_ids *pair,
static bool match_either_id(const struct asymmetric_key_id **pair,
			    const struct asymmetric_key_id *single)
{
	return (asymmetric_key_id_same(pair->id[0], single) ||
		asymmetric_key_id_same(pair->id[1], single));
	return (asymmetric_key_id_same(pair[0], single) ||
		asymmetric_key_id_same(pair[1], single));
}

static int key_or_keyring_common(struct key *dest_keyring,
@@ -140,20 +140,22 @@ static int key_or_keyring_common(struct key *dest_keyring,
	sig = payload->data[asym_auth];
	if (!sig)
		return -ENOPKG;
	if (!sig->auth_ids[0] && !sig->auth_ids[1])
	if (!sig->auth_ids[0] && !sig->auth_ids[1] && !sig->auth_ids[2])
		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);
						  sig->auth_ids[1],
						  sig->auth_ids[2], false);
			if (IS_ERR(key))
				key = NULL;
		} else if (trusted->type == &key_type_asymmetric) {
			const struct asymmetric_key_ids *signer_ids;
			const struct asymmetric_key_id **signer_ids;

			signer_ids = asymmetric_key_ids(trusted);
			signer_ids = (const struct asymmetric_key_id **)
				asymmetric_key_ids(trusted)->id;

			/*
			 * The auth_ids come from the candidate key (the
@@ -164,22 +166,29 @@ static int key_or_keyring_common(struct key *dest_keyring,
			 * 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.
			 * The first auth_id is the preferred id, 2nd and
			 * 3rd are the fallbacks. If exactly one of
			 * auth_ids[0] and auth_ids[1] is present, it may
			 * match either signer_ids[0] or signed_ids[1].
			 * If both are present the first one may match
			 * either signed_id but the second one must match
			 * the second signer_id. If neither of them is
			 * available, auth_ids[2] is matched against
			 * signer_ids[2] as a fallback.
			 */
			if (!sig->auth_ids[0] || !sig->auth_ids[1]) {
			if (!sig->auth_ids[0] && !sig->auth_ids[1]) {
				if (asymmetric_key_id_same(signer_ids[2],
							   sig->auth_ids[2]))
					key = __key_get(trusted);

			} else 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],
			} else if (asymmetric_key_id_same(signer_ids[1],
							  sig->auth_ids[1]) &&
				   match_either_id(signer_ids,
						   sig->auth_ids[0])) {
@@ -193,7 +202,8 @@ static int key_or_keyring_common(struct key *dest_keyring,
	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);
					  sig->auth_ids[1], sig->auth_ids[2],
					  false);
		if (IS_ERR(key))
			key = NULL;
	}
+10 −0
Original line number Diff line number Diff line
@@ -441,8 +441,18 @@ int x509_note_issuer(void *context, size_t hdrlen,
		     const void *value, size_t vlen)
{
	struct x509_parse_context *ctx = context;
	struct asymmetric_key_id *kid;

	ctx->cert->raw_issuer = value;
	ctx->cert->raw_issuer_size = vlen;

	if (!ctx->cert->sig->auth_ids[2]) {
		kid = asymmetric_key_generate_id(value, vlen, "", 0);
		if (IS_ERR(kid))
			return PTR_ERR(kid);
		ctx->cert->sig->auth_ids[2] = kid;
	}

	return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->issuer, vlen);
}

+10 −0
Original line number Diff line number Diff line
@@ -223,6 +223,13 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
		goto error_free_desc;
	kids->id[0] = cert->id;
	kids->id[1] = cert->skid;
	kids->id[2] = asymmetric_key_generate_id(cert->raw_subject,
						 cert->raw_subject_size,
						 "", 0);
	if (IS_ERR(kids->id[2])) {
		ret = PTR_ERR(kids->id[2]);
		goto error_free_kids;
	}

	/* We're pinning the module by being linked against it */
	__module_get(public_key_subtype.owner);
@@ -239,8 +246,11 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
	cert->skid = NULL;
	cert->sig = NULL;
	desc = NULL;
	kids = NULL;
	ret = 0;

error_free_kids:
	kfree(kids);
error_free_desc:
	kfree(desc);
error_free_cert:
Loading