forked from Minki/linux
tpmdd updates for Linux v5.17
-----BEGIN PGP SIGNATURE----- iIgEABYIADAWIQRE6pSOnaBC00OEHEIaerohdGur0gUCYdzf7hIcamFya2tvQGtl cm5lbC5vcmcACgkQGnq6IXRrq9IA/AEA2sX9fNNYSYnUwvi/Ju+Y8BgW4pA+GvA0 L8iSuUkWdssA/iQFdQ3vyDK0CI56G1jerKMyT7o8QEuJmUYogTRV7+oA =7q7g -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
dabd40ecaf
@ -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;
|
||||
}
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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:
|
||||
|
@ -61,9 +61,7 @@ enum tis_defaults {
|
||||
};
|
||||
|
||||
/*
|
||||
* clear_interruption clear the pending interrupt.
|
||||
* @param: tpm_dev, the tpm device device.
|
||||
* @return: the interrupt status value.
|
||||
* clear the pending interrupt.
|
||||
*/
|
||||
static u8 clear_interruption(struct st33zp24_dev *tpm_dev)
|
||||
{
|
||||
@ -72,12 +70,10 @@ static u8 clear_interruption(struct st33zp24_dev *tpm_dev)
|
||||
tpm_dev->ops->recv(tpm_dev->phy_id, TPM_INT_STATUS, &interrupt, 1);
|
||||
tpm_dev->ops->send(tpm_dev->phy_id, TPM_INT_STATUS, &interrupt, 1);
|
||||
return interrupt;
|
||||
} /* clear_interruption() */
|
||||
}
|
||||
|
||||
/*
|
||||
* st33zp24_cancel, cancel the current command execution or
|
||||
* set STS to COMMAND READY.
|
||||
* @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h
|
||||
* cancel the current command execution or set STS to COMMAND READY.
|
||||
*/
|
||||
static void st33zp24_cancel(struct tpm_chip *chip)
|
||||
{
|
||||
@ -86,12 +82,10 @@ static void st33zp24_cancel(struct tpm_chip *chip)
|
||||
|
||||
data = TPM_STS_COMMAND_READY;
|
||||
tpm_dev->ops->send(tpm_dev->phy_id, TPM_STS, &data, 1);
|
||||
} /* st33zp24_cancel() */
|
||||
}
|
||||
|
||||
/*
|
||||
* st33zp24_status return the TPM_STS register
|
||||
* @param: chip, the tpm chip description
|
||||
* @return: the TPM_STS register value.
|
||||
* return the TPM_STS register
|
||||
*/
|
||||
static u8 st33zp24_status(struct tpm_chip *chip)
|
||||
{
|
||||
@ -100,12 +94,10 @@ static u8 st33zp24_status(struct tpm_chip *chip)
|
||||
|
||||
tpm_dev->ops->recv(tpm_dev->phy_id, TPM_STS, &data, 1);
|
||||
return data;
|
||||
} /* st33zp24_status() */
|
||||
}
|
||||
|
||||
/*
|
||||
* check_locality if the locality is active
|
||||
* @param: chip, the tpm chip description
|
||||
* @return: true if LOCALITY0 is active, otherwise false
|
||||
* if the locality is active
|
||||
*/
|
||||
static bool check_locality(struct tpm_chip *chip)
|
||||
{
|
||||
@ -120,13 +112,8 @@ static bool check_locality(struct tpm_chip *chip)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
} /* check_locality() */
|
||||
}
|
||||
|
||||
/*
|
||||
* request_locality request the TPM locality
|
||||
* @param: chip, the chip description
|
||||
* @return: the active locality or negative value.
|
||||
*/
|
||||
static int request_locality(struct tpm_chip *chip)
|
||||
{
|
||||
struct st33zp24_dev *tpm_dev = dev_get_drvdata(&chip->dev);
|
||||
@ -153,12 +140,8 @@ static int request_locality(struct tpm_chip *chip)
|
||||
|
||||
/* could not get locality */
|
||||
return -EACCES;
|
||||
} /* request_locality() */
|
||||
}
|
||||
|
||||
/*
|
||||
* release_locality release the active locality
|
||||
* @param: chip, the tpm chip description.
|
||||
*/
|
||||
static void release_locality(struct tpm_chip *chip)
|
||||
{
|
||||
struct st33zp24_dev *tpm_dev = dev_get_drvdata(&chip->dev);
|
||||
@ -171,8 +154,6 @@ static void release_locality(struct tpm_chip *chip)
|
||||
|
||||
/*
|
||||
* get_burstcount return the burstcount value
|
||||
* @param: chip, the chip description
|
||||
* return: the burstcount or negative value.
|
||||
*/
|
||||
static int get_burstcount(struct tpm_chip *chip)
|
||||
{
|
||||
@ -200,18 +181,8 @@ static int get_burstcount(struct tpm_chip *chip)
|
||||
msleep(TPM_TIMEOUT);
|
||||
} while (time_before(jiffies, stop));
|
||||
return -EBUSY;
|
||||
} /* get_burstcount() */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* wait_for_tpm_stat_cond
|
||||
* @param: chip, chip description
|
||||
* @param: mask, expected mask value
|
||||
* @param: check_cancel, does the command expected to be canceled ?
|
||||
* @param: canceled, did we received a cancel request ?
|
||||
* @return: true if status == mask or if the command is canceled.
|
||||
* false in other cases.
|
||||
*/
|
||||
static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask,
|
||||
bool check_cancel, bool *canceled)
|
||||
{
|
||||
@ -228,13 +199,7 @@ static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask,
|
||||
}
|
||||
|
||||
/*
|
||||
* wait_for_stat wait for a TPM_STS value
|
||||
* @param: chip, the tpm chip description
|
||||
* @param: mask, the value mask to wait
|
||||
* @param: timeout, the timeout
|
||||
* @param: queue, the wait queue.
|
||||
* @param: check_cancel, does the command can be cancelled ?
|
||||
* @return: the tpm status, 0 if success, -ETIME if timeout is reached.
|
||||
* wait for a TPM_STS value
|
||||
*/
|
||||
static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
|
||||
wait_queue_head_t *queue, bool check_cancel)
|
||||
@ -292,15 +257,8 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
|
||||
}
|
||||
|
||||
return -ETIME;
|
||||
} /* wait_for_stat() */
|
||||
}
|
||||
|
||||
/*
|
||||
* recv_data receive data
|
||||
* @param: chip, the tpm chip description
|
||||
* @param: buf, the buffer where the data are received
|
||||
* @param: count, the number of data to receive
|
||||
* @return: the number of bytes read from TPM FIFO.
|
||||
*/
|
||||
static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||
{
|
||||
struct st33zp24_dev *tpm_dev = dev_get_drvdata(&chip->dev);
|
||||
@ -325,12 +283,6 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||
return size;
|
||||
}
|
||||
|
||||
/*
|
||||
* tpm_ioserirq_handler the serirq irq handler
|
||||
* @param: irq, the tpm chip description
|
||||
* @param: dev_id, the description of the chip
|
||||
* @return: the status of the handler.
|
||||
*/
|
||||
static irqreturn_t tpm_ioserirq_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct tpm_chip *chip = dev_id;
|
||||
@ -341,16 +293,10 @@ static irqreturn_t tpm_ioserirq_handler(int irq, void *dev_id)
|
||||
disable_irq_nosync(tpm_dev->irq);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
} /* tpm_ioserirq_handler() */
|
||||
}
|
||||
|
||||
/*
|
||||
* st33zp24_send send TPM commands through the I2C bus.
|
||||
*
|
||||
* @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h
|
||||
* @param: buf, the buffer to send.
|
||||
* @param: count, the number of bytes to send.
|
||||
* @return: In case of success the number of bytes sent.
|
||||
* In other case, a < 0 value describing the issue.
|
||||
* send TPM commands through the I2C bus.
|
||||
*/
|
||||
static int st33zp24_send(struct tpm_chip *chip, unsigned char *buf,
|
||||
size_t len)
|
||||
@ -431,14 +377,6 @@ out_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* st33zp24_recv received TPM response through TPM phy.
|
||||
* @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h.
|
||||
* @param: buf, the buffer to store datas.
|
||||
* @param: count, the number of bytes to send.
|
||||
* @return: In case of success the number of bytes received.
|
||||
* In other case, a < 0 value describing the issue.
|
||||
*/
|
||||
static int st33zp24_recv(struct tpm_chip *chip, unsigned char *buf,
|
||||
size_t count)
|
||||
{
|
||||
@ -478,12 +416,6 @@ out:
|
||||
return size;
|
||||
}
|
||||
|
||||
/*
|
||||
* st33zp24_req_canceled
|
||||
* @param: chip, the tpm_chip description as specified in driver/char/tpm/tpm.h.
|
||||
* @param: status, the TPM status.
|
||||
* @return: Does TPM ready to compute a new command ? true.
|
||||
*/
|
||||
static bool st33zp24_req_canceled(struct tpm_chip *chip, u8 status)
|
||||
{
|
||||
return (status == TPM_STS_COMMAND_READY);
|
||||
@ -501,11 +433,7 @@ static const struct tpm_class_ops st33zp24_tpm = {
|
||||
};
|
||||
|
||||
/*
|
||||
* st33zp24_probe initialize the TPM device
|
||||
* @param: client, the i2c_client description (TPM I2C description).
|
||||
* @param: id, the i2c_device_id struct.
|
||||
* @return: 0 in case of success.
|
||||
* -1 in other case.
|
||||
* initialize the TPM device
|
||||
*/
|
||||
int st33zp24_probe(void *phy_id, const struct st33zp24_phy_ops *ops,
|
||||
struct device *dev, int irq, int io_lpcpd)
|
||||
@ -583,11 +511,6 @@ _tpm_clean_answer:
|
||||
}
|
||||
EXPORT_SYMBOL(st33zp24_probe);
|
||||
|
||||
/*
|
||||
* st33zp24_remove remove the TPM device
|
||||
* @param: tpm_data, the tpm phy.
|
||||
* @return: 0 in case of success.
|
||||
*/
|
||||
int st33zp24_remove(struct tpm_chip *chip)
|
||||
{
|
||||
tpm_chip_unregister(chip);
|
||||
@ -596,12 +519,6 @@ int st33zp24_remove(struct tpm_chip *chip)
|
||||
EXPORT_SYMBOL(st33zp24_remove);
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
/*
|
||||
* st33zp24_pm_suspend suspend the TPM device
|
||||
* @param: tpm_data, the tpm phy.
|
||||
* @param: mesg, the power management message.
|
||||
* @return: 0 in case of success.
|
||||
*/
|
||||
int st33zp24_pm_suspend(struct device *dev)
|
||||
{
|
||||
struct tpm_chip *chip = dev_get_drvdata(dev);
|
||||
@ -615,14 +532,9 @@ int st33zp24_pm_suspend(struct device *dev)
|
||||
ret = tpm_pm_suspend(dev);
|
||||
|
||||
return ret;
|
||||
} /* st33zp24_pm_suspend() */
|
||||
}
|
||||
EXPORT_SYMBOL(st33zp24_pm_suspend);
|
||||
|
||||
/*
|
||||
* st33zp24_pm_resume resume the TPM device
|
||||
* @param: tpm_data, the tpm phy.
|
||||
* @return: 0 in case of success.
|
||||
*/
|
||||
int st33zp24_pm_resume(struct device *dev)
|
||||
{
|
||||
struct tpm_chip *chip = dev_get_drvdata(dev);
|
||||
@ -640,7 +552,7 @@ int st33zp24_pm_resume(struct device *dev)
|
||||
tpm1_do_selftest(chip);
|
||||
}
|
||||
return ret;
|
||||
} /* st33zp24_pm_resume() */
|
||||
}
|
||||
EXPORT_SYMBOL(st33zp24_pm_resume);
|
||||
#endif
|
||||
|
||||
|
@ -444,7 +444,7 @@ static int tpm_add_char_device(struct tpm_chip *chip)
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
|
||||
if (chip->flags & TPM_CHIP_FLAG_TPM2 && !tpm_is_firmware_upgrade(chip)) {
|
||||
rc = cdev_device_add(&chip->cdevs, &chip->devs);
|
||||
if (rc) {
|
||||
dev_err(&chip->devs,
|
||||
@ -474,13 +474,21 @@ static void tpm_del_char_device(struct tpm_chip *chip)
|
||||
|
||||
/* Make the driver uncallable. */
|
||||
down_write(&chip->ops_sem);
|
||||
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
|
||||
if (!tpm_chip_start(chip)) {
|
||||
tpm2_shutdown(chip, TPM2_SU_CLEAR);
|
||||
tpm_chip_stop(chip);
|
||||
|
||||
/*
|
||||
* Check if chip->ops is still valid: In case that the controller
|
||||
* drivers shutdown handler unregisters the controller in its
|
||||
* shutdown handler we are called twice and chip->ops to NULL.
|
||||
*/
|
||||
if (chip->ops) {
|
||||
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
|
||||
if (!tpm_chip_start(chip)) {
|
||||
tpm2_shutdown(chip, TPM2_SU_CLEAR);
|
||||
tpm_chip_stop(chip);
|
||||
}
|
||||
}
|
||||
chip->ops = NULL;
|
||||
}
|
||||
chip->ops = NULL;
|
||||
up_write(&chip->ops_sem);
|
||||
}
|
||||
|
||||
@ -488,7 +496,8 @@ static void tpm_del_legacy_sysfs(struct tpm_chip *chip)
|
||||
{
|
||||
struct attribute **i;
|
||||
|
||||
if (chip->flags & (TPM_CHIP_FLAG_TPM2 | TPM_CHIP_FLAG_VIRTUAL))
|
||||
if (chip->flags & (TPM_CHIP_FLAG_TPM2 | TPM_CHIP_FLAG_VIRTUAL) ||
|
||||
tpm_is_firmware_upgrade(chip))
|
||||
return;
|
||||
|
||||
sysfs_remove_link(&chip->dev.parent->kobj, "ppi");
|
||||
@ -506,7 +515,8 @@ static int tpm_add_legacy_sysfs(struct tpm_chip *chip)
|
||||
struct attribute **i;
|
||||
int rc;
|
||||
|
||||
if (chip->flags & (TPM_CHIP_FLAG_TPM2 | TPM_CHIP_FLAG_VIRTUAL))
|
||||
if (chip->flags & (TPM_CHIP_FLAG_TPM2 | TPM_CHIP_FLAG_VIRTUAL) ||
|
||||
tpm_is_firmware_upgrade(chip))
|
||||
return 0;
|
||||
|
||||
rc = compat_only_sysfs_link_entry_to_kobj(
|
||||
@ -536,7 +546,7 @@ static int tpm_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait)
|
||||
|
||||
static int tpm_add_hwrng(struct tpm_chip *chip)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_HW_RANDOM_TPM))
|
||||
if (!IS_ENABLED(CONFIG_HW_RANDOM_TPM) || tpm_is_firmware_upgrade(chip))
|
||||
return 0;
|
||||
|
||||
snprintf(chip->hwrng_name, sizeof(chip->hwrng_name),
|
||||
@ -550,6 +560,9 @@ static int tpm_get_pcr_allocation(struct tpm_chip *chip)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (tpm_is_firmware_upgrade(chip))
|
||||
return 0;
|
||||
|
||||
rc = (chip->flags & TPM_CHIP_FLAG_TPM2) ?
|
||||
tpm2_get_pcr_allocation(chip) :
|
||||
tpm1_get_pcr_allocation(chip);
|
||||
@ -612,7 +625,7 @@ int tpm_chip_register(struct tpm_chip *chip)
|
||||
return 0;
|
||||
|
||||
out_hwrng:
|
||||
if (IS_ENABLED(CONFIG_HW_RANDOM_TPM))
|
||||
if (IS_ENABLED(CONFIG_HW_RANDOM_TPM) && !tpm_is_firmware_upgrade(chip))
|
||||
hwrng_unregister(&chip->hwrng);
|
||||
out_ppi:
|
||||
tpm_bios_log_teardown(chip);
|
||||
@ -637,10 +650,10 @@ EXPORT_SYMBOL_GPL(tpm_chip_register);
|
||||
void tpm_chip_unregister(struct tpm_chip *chip)
|
||||
{
|
||||
tpm_del_legacy_sysfs(chip);
|
||||
if (IS_ENABLED(CONFIG_HW_RANDOM_TPM))
|
||||
if (IS_ENABLED(CONFIG_HW_RANDOM_TPM) && !tpm_is_firmware_upgrade(chip))
|
||||
hwrng_unregister(&chip->hwrng);
|
||||
tpm_bios_log_teardown(chip);
|
||||
if (chip->flags & TPM_CHIP_FLAG_TPM2)
|
||||
if (chip->flags & TPM_CHIP_FLAG_TPM2 && !tpm_is_firmware_upgrade(chip))
|
||||
cdev_device_del(&chip->cdevs, &chip->devs);
|
||||
tpm_del_char_device(chip);
|
||||
}
|
||||
|
@ -480,6 +480,9 @@ void tpm_sysfs_add_device(struct tpm_chip *chip)
|
||||
|
||||
WARN_ON(chip->groups_cnt != 0);
|
||||
|
||||
if (tpm_is_firmware_upgrade(chip))
|
||||
return;
|
||||
|
||||
if (chip->flags & TPM_CHIP_FLAG_TPM2)
|
||||
chip->groups[chip->groups_cnt++] = &tpm2_dev_group;
|
||||
else
|
||||
|
@ -745,6 +745,12 @@ int tpm2_auto_startup(struct tpm_chip *chip)
|
||||
rc = tpm2_get_cc_attrs_tbl(chip);
|
||||
|
||||
out:
|
||||
if (rc == TPM2_RC_UPGRADE) {
|
||||
dev_info(&chip->dev, "TPM in field upgrade mode, requires firmware upgrade\n");
|
||||
chip->flags |= TPM_CHIP_FLAG_FIRMWARE_UPGRADE;
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
if (rc > 0)
|
||||
rc = -ENODEV;
|
||||
return rc;
|
||||
|
@ -950,9 +950,11 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
|
||||
priv->timeout_max = TPM_TIMEOUT_USECS_MAX;
|
||||
priv->phy_ops = phy_ops;
|
||||
|
||||
dev_set_drvdata(&chip->dev, priv);
|
||||
|
||||
rc = tpm_tis_read32(priv, TPM_DID_VID(0), &vendor);
|
||||
if (rc < 0)
|
||||
goto out_err;
|
||||
return rc;
|
||||
|
||||
priv->manufacturer_id = vendor;
|
||||
|
||||
@ -962,8 +964,6 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
|
||||
priv->timeout_max = TIS_TIMEOUT_MAX_ATML;
|
||||
}
|
||||
|
||||
dev_set_drvdata(&chip->dev, priv);
|
||||
|
||||
if (is_bsw()) {
|
||||
priv->ilb_base_addr = ioremap(INTEL_LEGACY_BLK_BASE_ADDR,
|
||||
ILB_REMAP_SIZE);
|
||||
@ -994,7 +994,15 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
|
||||
intmask |= TPM_INTF_CMD_READY_INT | TPM_INTF_LOCALITY_CHANGE_INT |
|
||||
TPM_INTF_DATA_AVAIL_INT | TPM_INTF_STS_VALID_INT;
|
||||
intmask &= ~TPM_GLOBAL_INT_ENABLE;
|
||||
|
||||
rc = request_locality(chip, 0);
|
||||
if (rc < 0) {
|
||||
rc = -ENODEV;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality), intmask);
|
||||
release_locality(chip, 0);
|
||||
|
||||
rc = tpm_chip_start(chip);
|
||||
if (rc)
|
||||
|
@ -628,6 +628,19 @@ static bool tpm_cr50_i2c_req_canceled(struct tpm_chip *chip, u8 status)
|
||||
return status == TPM_STS_COMMAND_READY;
|
||||
}
|
||||
|
||||
static bool tpm_cr50_i2c_is_firmware_power_managed(struct device *dev)
|
||||
{
|
||||
u8 val;
|
||||
int ret;
|
||||
|
||||
/* This flag should default true when the device property is not present */
|
||||
ret = device_property_read_u8(dev, "firmware-power-managed", &val);
|
||||
if (ret)
|
||||
return true;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static const struct tpm_class_ops cr50_i2c = {
|
||||
.flags = TPM_OPS_AUTO_STARTUP,
|
||||
.status = &tpm_cr50_i2c_tis_status,
|
||||
@ -686,7 +699,8 @@ static int tpm_cr50_i2c_probe(struct i2c_client *client)
|
||||
|
||||
/* cr50 is a TPM 2.0 chip */
|
||||
chip->flags |= TPM_CHIP_FLAG_TPM2;
|
||||
chip->flags |= TPM_CHIP_FLAG_FIRMWARE_POWER_MANAGED;
|
||||
if (tpm_cr50_i2c_is_firmware_power_managed(dev))
|
||||
chip->flags |= TPM_CHIP_FLAG_FIRMWARE_POWER_MANAGED;
|
||||
|
||||
/* Default timeouts */
|
||||
chip->timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
|
||||
|
@ -36,6 +36,9 @@
|
||||
#define TPM_CR50_FW_VER(l) (0x0f90 | ((l) << 12))
|
||||
#define TPM_CR50_MAX_FW_VER_LEN 64
|
||||
|
||||
/* Default quality for hwrng. */
|
||||
#define TPM_CR50_DEFAULT_RNG_QUALITY 700
|
||||
|
||||
struct cr50_spi_phy {
|
||||
struct tpm_tis_spi_phy spi_phy;
|
||||
|
||||
@ -182,6 +185,19 @@ static int cr50_spi_flow_control(struct tpm_tis_spi_phy *phy,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool tpm_cr50_spi_is_firmware_power_managed(struct device *dev)
|
||||
{
|
||||
u8 val;
|
||||
int ret;
|
||||
|
||||
/* This flag should default true when the device property is not present */
|
||||
ret = device_property_read_u8(dev, "firmware-power-managed", &val);
|
||||
if (ret)
|
||||
return true;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static int tpm_tis_spi_cr50_transfer(struct tpm_tis_data *data, u32 addr, u16 len,
|
||||
u8 *in, const u8 *out)
|
||||
{
|
||||
@ -264,6 +280,7 @@ int cr50_spi_probe(struct spi_device *spi)
|
||||
phy = &cr50_phy->spi_phy;
|
||||
phy->flow_control = cr50_spi_flow_control;
|
||||
phy->wake_after = jiffies;
|
||||
phy->priv.rng_quality = TPM_CR50_DEFAULT_RNG_QUALITY;
|
||||
init_completion(&phy->ready);
|
||||
|
||||
cr50_phy->access_delay = CR50_NOIRQ_ACCESS_DELAY;
|
||||
@ -305,7 +322,8 @@ int cr50_spi_probe(struct spi_device *spi)
|
||||
cr50_print_fw_version(&phy->priv);
|
||||
|
||||
chip = dev_get_drvdata(&spi->dev);
|
||||
chip->flags |= TPM_CHIP_FLAG_FIRMWARE_POWER_MANAGED;
|
||||
if (tpm_cr50_spi_is_firmware_power_managed(&spi->dev))
|
||||
chip->flags |= TPM_CHIP_FLAG_FIRMWARE_POWER_MANAGED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ extern void public_key_free(struct public_key *key);
|
||||
* Public key cryptography signature data
|
||||
*/
|
||||
struct public_key_signature {
|
||||
struct asymmetric_key_id *auth_ids[2];
|
||||
struct asymmetric_key_id *auth_ids[3];
|
||||
u8 *s; /* Signature */
|
||||
u8 *digest;
|
||||
u32 s_size; /* Number of bytes in signature */
|
||||
|
@ -53,7 +53,7 @@ struct asymmetric_key_id {
|
||||
};
|
||||
|
||||
struct asymmetric_key_ids {
|
||||
void *id[2];
|
||||
void *id[3];
|
||||
};
|
||||
|
||||
extern bool asymmetric_key_id_same(const struct asymmetric_key_id *kid1,
|
||||
@ -81,6 +81,7 @@ const struct public_key *asymmetric_key_public_key(const struct key *key)
|
||||
extern 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);
|
||||
|
||||
/*
|
||||
|
@ -207,6 +207,7 @@ enum tpm2_return_codes {
|
||||
TPM2_RC_INITIALIZE = 0x0100, /* RC_VER1 */
|
||||
TPM2_RC_FAILURE = 0x0101,
|
||||
TPM2_RC_DISABLED = 0x0120,
|
||||
TPM2_RC_UPGRADE = 0x012D,
|
||||
TPM2_RC_COMMAND_CODE = 0x0143,
|
||||
TPM2_RC_TESTING = 0x090A, /* RC_WARN */
|
||||
TPM2_RC_REFERENCE_H0 = 0x0910,
|
||||
@ -278,6 +279,7 @@ enum tpm_chip_flags {
|
||||
TPM_CHIP_FLAG_HAVE_TIMEOUTS = BIT(4),
|
||||
TPM_CHIP_FLAG_ALWAYS_POWERED = BIT(5),
|
||||
TPM_CHIP_FLAG_FIRMWARE_POWER_MANAGED = BIT(6),
|
||||
TPM_CHIP_FLAG_FIRMWARE_UPGRADE = BIT(7),
|
||||
};
|
||||
|
||||
#define to_tpm_chip(d) container_of(d, struct tpm_chip, dev)
|
||||
@ -399,6 +401,14 @@ static inline void tpm_buf_append_u32(struct tpm_buf *buf, const u32 value)
|
||||
tpm_buf_append(buf, (u8 *) &value2, 4);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if TPM device is in the firmware upgrade mode.
|
||||
*/
|
||||
static inline bool tpm_is_firmware_upgrade(struct tpm_chip *chip)
|
||||
{
|
||||
return chip->flags & TPM_CHIP_FLAG_FIRMWARE_UPGRADE;
|
||||
}
|
||||
|
||||
static inline u32 tpm2_rc_value(u32 rc)
|
||||
{
|
||||
return (rc & BIT(7)) ? rc & 0xff : rc;
|
||||
|
@ -164,8 +164,6 @@ asn1_encode_oid(unsigned char *data, const unsigned char *end_data,
|
||||
|
||||
data_len -= 3;
|
||||
|
||||
ret = 0;
|
||||
|
||||
for (i = 2; i < oid_len; i++) {
|
||||
ret = asn1_encode_oid_digit(&d, &data_len, oid[i]);
|
||||
if (ret < 0)
|
||||
|
Loading…
Reference in New Issue
Block a user