diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2022-01-11 12:58:41 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2022-01-11 12:58:41 -0800 |
commit | dabd40ecaf693a18afd4c59c8d7280610d95b66e (patch) | |
tree | 880b7680689a44b6e514508d30de36295fe2e700 | |
parent | 4aa1b8257fba5931511a7e152bcbbb3dd673c6c1 (diff) | |
parent | d99a8af48a3de727173415ccb17f6b6ba60d5573 (diff) |
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
-rw-r--r-- | crypto/asymmetric_keys/asymmetric_type.c | 57 | ||||
-rw-r--r-- | crypto/asymmetric_keys/pkcs7_trust.c | 6 | ||||
-rw-r--r-- | crypto/asymmetric_keys/restrict.c | 48 | ||||
-rw-r--r-- | crypto/asymmetric_keys/x509_cert_parser.c | 10 | ||||
-rw-r--r-- | crypto/asymmetric_keys/x509_public_key.c | 10 | ||||
-rw-r--r-- | drivers/char/tpm/st33zp24/st33zp24.c | 122 | ||||
-rw-r--r-- | drivers/char/tpm/tpm-chip.c | 37 | ||||
-rw-r--r-- | drivers/char/tpm/tpm-sysfs.c | 3 | ||||
-rw-r--r-- | drivers/char/tpm/tpm2-cmd.c | 6 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_tis_core.c | 14 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_tis_i2c_cr50.c | 16 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_tis_spi_cr50.c | 20 | ||||
-rw-r--r-- | include/crypto/public_key.h | 2 | ||||
-rw-r--r-- | include/keys/asymmetric-type.h | 3 | ||||
-rw-r--r-- | include/linux/tpm.h | 10 | ||||
-rw-r--r-- | lib/asn1_encoder.c | 2 |
16 files changed, 205 insertions, 161 deletions
diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c index ad8af3d70ac0..41a2f0eb4ce4 100644 --- a/crypto/asymmetric_keys/asymmetric_type.c +++ b/crypto/asymmetric_keys/asymmetric_type.c @@ -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) @@ -270,14 +283,27 @@ static bool asymmetric_key_cmp_partial(const struct key *key, } /* + * 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. * * 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; } diff --git a/crypto/asymmetric_keys/pkcs7_trust.c b/crypto/asymmetric_keys/pkcs7_trust.c index b531df2013c4..9a87c34ed173 100644 --- a/crypto/asymmetric_keys/pkcs7_trust.c +++ b/crypto/asymmetric_keys/pkcs7_trust.c @@ -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)); diff --git a/crypto/asymmetric_keys/restrict.c b/crypto/asymmetric_keys/restrict.c index 84cefe3b3585..6b1ac5f5896a 100644 --- a/crypto/asymmetric_keys/restrict.c +++ b/crypto/asymmetric_keys/restrict.c @@ -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; } diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c index 6d003096b5bc..083405eb80c3 100644 --- a/crypto/asymmetric_keys/x509_cert_parser.c +++ b/crypto/asymmetric_keys/x509_cert_parser.c @@ -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); } diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c index 3d45161b271a..fe14cae115b5 100644 --- a/crypto/asymmetric_keys/x509_public_key.c +++ b/crypto/asymmetric_keys/x509_public_key.c @@ -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: diff --git a/drivers/char/tpm/st33zp24/st33zp24.c b/drivers/char/tpm/st33zp24/st33zp24.c index 4ec10ab5e576..ce9efb73c144 100644 --- a/drivers/char/tpm/st33zp24/st33zp24.c +++ b/drivers/char/tpm/st33zp24/st33zp24.c @@ -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 diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index ddaeceb7e109..b009e7479b70 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -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); } diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c index 63f03cfb8e6a..54c71473aa29 100644 --- a/drivers/char/tpm/tpm-sysfs.c +++ b/drivers/char/tpm/tpm-sysfs.c @@ -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 diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index a25815a6f625..4704fa553098 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -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; diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c index b2659a4c4016..dc56b976d816 100644 --- a/drivers/char/tpm/tpm_tis_core.c +++ b/drivers/char/tpm/tpm_tis_core.c @@ -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) diff --git a/drivers/char/tpm/tpm_tis_i2c_cr50.c b/drivers/char/tpm/tpm_tis_i2c_cr50.c index c89278103703..f6c0affbb456 100644 --- a/drivers/char/tpm/tpm_tis_i2c_cr50.c +++ b/drivers/char/tpm/tpm_tis_i2c_cr50.c @@ -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); diff --git a/drivers/char/tpm/tpm_tis_spi_cr50.c b/drivers/char/tpm/tpm_tis_spi_cr50.c index ea759af25634..7bf123d3c537 100644 --- a/drivers/char/tpm/tpm_tis_spi_cr50.c +++ b/drivers/char/tpm/tpm_tis_spi_cr50.c @@ -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; } diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h index f603325c0c30..68f7aa2a7e55 100644 --- a/include/crypto/public_key.h +++ b/include/crypto/public_key.h @@ -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 */ diff --git a/include/keys/asymmetric-type.h b/include/keys/asymmetric-type.h index c432fdb8547f..6c5d4963e15b 100644 --- a/include/keys/asymmetric-type.h +++ b/include/keys/asymmetric-type.h @@ -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); /* diff --git a/include/linux/tpm.h b/include/linux/tpm.h index 12d827734686..dfeb25a0362d 100644 --- a/include/linux/tpm.h +++ b/include/linux/tpm.h @@ -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; diff --git a/lib/asn1_encoder.c b/lib/asn1_encoder.c index 27bbe891714f..0fd3c454a468 100644 --- a/lib/asn1_encoder.c +++ b/lib/asn1_encoder.c @@ -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) |