Commit dabd40ec authored by Linus Torvalds's avatar Linus Torvalds

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
......@@ -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 @@ static int st33zp24_send(struct tpm_chip *chip, unsigned char *buf,
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 @@ static int st33zp24_recv(struct tpm_chip *chip, unsigned char *buf,
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 @@ int st33zp24_probe(void *phy_id, const struct st33zp24_phy_ops *ops,
}
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)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment