From nobody Fri Dec 19 16:17:57 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BCDE418D658; Fri, 5 Dec 2025 03:02:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764903743; cv=none; b=dB5HJe3rWqcO8+r4NRd8rO2fiG/Gwux8HmqE/pLN6NcpRGV4ih/KeFFif7M1KF1/c4bDyMdRJjC65Nlz6iET+RAfIJ3IOEAPq9VhPO16jX2zOOT164Tkx55gZtpO0wbHLXKxzjfUQz6rDZV16CysdYFuRGpcwteZRO4UoBKy7pA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764903743; c=relaxed/simple; bh=n+nicI4U7xTxw8sxuUVOoiYTLjUSg7PHlKmjjBU49fg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=cKGOPrGL6MDRgJ5H7a+XIX1hQjY3CbWUo4Wsl2PN1PjxhpmagK+VO/8W1oX7d+fj1tTynqKXKnEEwn7Gqzv3XLKeTXSweDl6+l1T9Arpl1ptpXASoi2OrqOwLmHxzctbL+jeeR1/HK88WrFAefLQaT4fYKFYbG+EwamzknfQb6c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=olUico2g; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="olUico2g" Received: by smtp.kernel.org (Postfix) with ESMTPSA id C5118C4CEFB; Fri, 5 Dec 2025 03:02:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1764903743; bh=n+nicI4U7xTxw8sxuUVOoiYTLjUSg7PHlKmjjBU49fg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=olUico2gh/sAym91BxBwpq6HwyjuP2M9Oi1lHlUBRXiR9eUcYVKVjAdD95hsb2S2N pK3W0HKKsfylnFbPRi2rrjHbqDjRstYVvEzp3BO1ziQGjQ00XJ50zCayZXcR3YtOke G+n7uCbm5hfhgz8UUw6LFCHA7CMtaZ2Aa32hi5QxYOYg3GTZoc0jFSk64y2lfpwgdq r8Bh40aKU+BnphLB+Cn7h7exz+ojy3D+PauUDaPddD82pnGUut3ohTBd7JPCB6K7BU vYWD0SP+XrtrXnTmA99asm4/BTdV2JVpNLQ/49px9x28OiMfGi1Y1yHQ42oo6Hzffe RHqYcG9hF8LaA== From: Jarkko Sakkinen To: linux-integrity@vger.kernel.org Cc: Jarkko Sakkinen , Peter Huewe , Jason Gunthorpe , James Bottomley , Mimi Zohar , David Howells , Paul Moore , James Morris , "Serge E. Hallyn" , linux-kernel@vger.kernel.org (open list), keyrings@vger.kernel.org (open list:KEYS-TRUSTED), linux-security-module@vger.kernel.org (open list:SECURITY SUBSYSTEM) Subject: [PATCH v2 1/2] KEYS: trusted: Re-orchestrate tpm2_read_public() calls Date: Fri, 5 Dec 2025 05:02:04 +0200 Message-ID: <20251205030205.140842-2-jarkko@kernel.org> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20251205030205.140842-1-jarkko@kernel.org> References: <20251205030205.140842-1-jarkko@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" tpm2_load_cmd() and tpm2_unseal_cmd() use the same parent, and calls to tpm_buf_append_name() cause the exact same TPM2_ReadPublic command to be sent to the chip, causing unnecessary traffic. 1. Export tpm2_read_public in order to make it callable from 'trusted_tpm2'. 2. Re-orchestrate tpm2_seal_trusted() and tpm2_unseal_trusted() in order to halve the name resolutions required: 2a. Move tpm2_read_public() calls into trusted_tpm2. 2b. Pass TPM name to tpm_buf_append_name(). 2c. Rework tpm_buf_append_name() to use the pre-resolved name. Signed-off-by: Jarkko Sakkinen --- v2:=20 - No changes. --- drivers/char/tpm/tpm2-cmd.c | 3 +- drivers/char/tpm/tpm2-sessions.c | 95 +++++------------ include/linux/tpm.h | 10 +- security/keys/trusted-keys/trusted_tpm2.c | 124 ++++++++++++++-------- 4 files changed, 118 insertions(+), 114 deletions(-) diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index 3a77be7ebf4a..1f561ad3bdcf 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -202,7 +202,8 @@ int tpm2_pcr_extend(struct tpm_chip *chip, u32 pcr_idx, } =20 if (!disable_pcr_integrity) { - rc =3D tpm_buf_append_name(chip, &buf, pcr_idx, NULL); + rc =3D tpm_buf_append_name(chip, &buf, pcr_idx, (u8 *)&pcr_idx, + sizeof(u32)); if (rc) { tpm_buf_destroy(&buf); return rc; diff --git a/drivers/char/tpm/tpm2-sessions.c b/drivers/char/tpm/tpm2-sessi= ons.c index 4149379665c4..e33be09446ff 100644 --- a/drivers/char/tpm/tpm2-sessions.c +++ b/drivers/char/tpm/tpm2-sessions.c @@ -136,8 +136,8 @@ struct tpm2_auth { * handle, but they are part of the session by name, which * we must compute and remember */ - u32 name_h[AUTH_MAX_NAMES]; u8 name[AUTH_MAX_NAMES][2 + SHA512_DIGEST_SIZE]; + u16 name_size_tbl[AUTH_MAX_NAMES]; }; =20 #ifdef CONFIG_TCG_TPM2_HMAC @@ -163,7 +163,17 @@ static int name_size(const u8 *name) } } =20 -static int tpm2_read_public(struct tpm_chip *chip, u32 handle, void *name) +/** + * tpm2_read_public: Resolve TPM name for a handle + * @chip: TPM chip to use. + * @handle: TPM handle. + * @name: A buffer for returning the name blob. Must have a + * capacity of 'SHA512_DIGET_SIZE + 2' bytes at minimum + * + * Returns size of TPM handle name of success. + * Returns tpm_transmit_cmd error codes when TPM2_ReadPublic fails. + */ +int tpm2_read_public(struct tpm_chip *chip, u32 handle, void *name) { u32 mso =3D tpm2_handle_mso(handle); off_t offset =3D TPM_HEADER_SIZE; @@ -219,14 +229,16 @@ static int tpm2_read_public(struct tpm_chip *chip, u3= 2 handle, void *name) memcpy(name, &buf.data[offset], rc); return name_size_alg; } +EXPORT_SYMBOL_GPL(tpm2_read_public); #endif /* CONFIG_TCG_TPM2_HMAC */ =20 /** - * tpm_buf_append_name() - add a handle area to the buffer - * @chip: the TPM chip structure - * @buf: The buffer to be appended - * @handle: The handle to be appended - * @name: The name of the handle (may be NULL) + * tpm_buf_append_name() - Append a handle and store TPM name + * @chip: TPM chip to use. + * @buf: TPM buffer containing the TPM command in-transit. + * @handle: TPM handle to be appended. + * @name: TPM name of the handle + * @name_size: Size of the TPM name. * * In order to compute session HMACs, we need to know the names of the * objects pointed to by the handles. For most objects, this is simply @@ -243,15 +255,14 @@ static int tpm2_read_public(struct tpm_chip *chip, u3= 2 handle, void *name) * will be caused by an incorrect programming model and indicated by a * kernel message. * - * Ends the authorization session on failure. + * Returns zero on success. + * Returns -EIO when the authorization area state is malformed. */ int tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf, - u32 handle, u8 *name) + u32 handle, u8 *name, u16 name_size) { #ifdef CONFIG_TCG_TPM2_HMAC - enum tpm2_mso_type mso =3D tpm2_handle_mso(handle); struct tpm2_auth *auth; - u16 name_size_alg; int slot; int ret; #endif @@ -276,36 +287,15 @@ int tpm_buf_append_name(struct tpm_chip *chip, struct= tpm_buf *buf, } tpm_buf_append_u32(buf, handle); auth->session +=3D 4; - - if (mso =3D=3D TPM2_MSO_PERSISTENT || - mso =3D=3D TPM2_MSO_VOLATILE || - mso =3D=3D TPM2_MSO_NVRAM) { - if (!name) { - ret =3D tpm2_read_public(chip, handle, auth->name[slot]); - if (ret < 0) - goto err; - - name_size_alg =3D ret; - } - } else { - if (name) { - dev_err(&chip->dev, "handle 0x%08x does not use a name\n", - handle); - ret =3D -EIO; - goto err; - } - } - - auth->name_h[slot] =3D handle; - if (name) - memcpy(auth->name[slot], name, name_size_alg); + memcpy(auth->name[slot], name, name_size); + auth->name_size_tbl[slot] =3D name_size; #endif return 0; =20 #ifdef CONFIG_TCG_TPM2_HMAC err: tpm2_end_auth_session(chip); - return tpm_ret_to_err(ret); + return ret; #endif } EXPORT_SYMBOL_GPL(tpm_buf_append_name); @@ -613,22 +603,8 @@ int tpm_buf_fill_hmac_session(struct tpm_chip *chip, s= truct tpm_buf *buf) attrs =3D chip->cc_attrs_tbl[i]; =20 handles =3D (attrs >> TPM2_CC_ATTR_CHANDLES) & GENMASK(2, 0); + offset_s +=3D handles * sizeof(u32); =20 - /* - * just check the names, it's easy to make mistakes. This - * would happen if someone added a handle via - * tpm_buf_append_u32() instead of tpm_buf_append_name() - */ - for (i =3D 0; i < handles; i++) { - u32 handle =3D tpm_buf_read_u32(buf, &offset_s); - - if (auth->name_h[i] !=3D handle) { - dev_err(&chip->dev, "invalid handle 0x%08x\n", handle); - ret =3D -EIO; - goto err; - } - } - /* point offset_s to the start of the sessions */ val =3D tpm_buf_read_u32(buf, &offset_s); /* point offset_p to the start of the parameters */ offset_p =3D offset_s + val; @@ -689,23 +665,8 @@ int tpm_buf_fill_hmac_session(struct tpm_chip *chip, s= truct tpm_buf *buf) /* ordinal is already BE */ sha256_update(&sctx, (u8 *)&head->ordinal, sizeof(head->ordinal)); /* add the handle names */ - for (i =3D 0; i < handles; i++) { - enum tpm2_mso_type mso =3D tpm2_handle_mso(auth->name_h[i]); - - if (mso =3D=3D TPM2_MSO_PERSISTENT || - mso =3D=3D TPM2_MSO_VOLATILE || - mso =3D=3D TPM2_MSO_NVRAM) { - ret =3D name_size(auth->name[i]); - if (ret < 0) - goto err; - - sha256_update(&sctx, auth->name[i], ret); - } else { - __be32 h =3D cpu_to_be32(auth->name_h[i]); - - sha256_update(&sctx, (u8 *)&h, 4); - } - } + for (i =3D 0; i < handles; i++) + sha256_update(&sctx, auth->name[i], auth->name_size_tbl[i]); if (offset_s !=3D tpm_buf_length(buf)) sha256_update(&sctx, &buf->data[offset_s], tpm_buf_length(buf) - offset_s); diff --git a/include/linux/tpm.h b/include/linux/tpm.h index 202da079d500..319ba75dd79a 100644 --- a/include/linux/tpm.h +++ b/include/linux/tpm.h @@ -530,7 +530,7 @@ static inline struct tpm2_auth *tpm2_chip_auth(struct t= pm_chip *chip) } =20 int tpm_buf_append_name(struct tpm_chip *chip, struct tpm_buf *buf, - u32 handle, u8 *name); + u32 handle, u8 *name, u16 name_size); void tpm_buf_append_hmac_session(struct tpm_chip *chip, struct tpm_buf *bu= f, u8 attributes, u8 *passphrase, int passphraselen); @@ -544,6 +544,7 @@ int tpm_buf_fill_hmac_session(struct tpm_chip *chip, st= ruct tpm_buf *buf); int tpm_buf_check_hmac_response(struct tpm_chip *chip, struct tpm_buf *buf, int rc); void tpm2_end_auth_session(struct tpm_chip *chip); +int tpm2_read_public(struct tpm_chip *chip, u32 handle, void *name); #else #include =20 @@ -567,6 +568,13 @@ static inline int tpm_buf_check_hmac_response(struct t= pm_chip *chip, { return rc; } + +static inline int tpm2_read_public(struct tpm_chip *chip, u32 handle, + void *name) +{ + memcpy(name, &handle, sizeof(u32)); + return sizeof(u32); +} #endif /* CONFIG_TCG_TPM2_HMAC */ =20 #endif diff --git a/security/keys/trusted-keys/trusted_tpm2.c b/security/keys/trus= ted-keys/trusted_tpm2.c index a7ea4a1c3bed..88bafbcc011a 100644 --- a/security/keys/trusted-keys/trusted_tpm2.c +++ b/security/keys/trusted-keys/trusted_tpm2.c @@ -233,8 +233,10 @@ int tpm2_seal_trusted(struct tpm_chip *chip, struct trusted_key_payload *payload, struct trusted_key_options *options) { + u8 parent_name[2 + SHA512_DIGEST_SIZE]; off_t offset =3D TPM_HEADER_SIZE; struct tpm_buf buf, sized; + u16 parent_name_size; int blob_len =3D 0; int hash; u32 flags; @@ -251,6 +253,12 @@ int tpm2_seal_trusted(struct tpm_chip *chip, if (rc) return rc; =20 + rc =3D tpm2_read_public(chip, options->keyhandle, parent_name); + if (rc < 0) + goto out_put; + + parent_name_size =3D rc; + rc =3D tpm2_start_auth_session(chip); if (rc) goto out_put; @@ -268,7 +276,8 @@ int tpm2_seal_trusted(struct tpm_chip *chip, goto out_put; } =20 - rc =3D tpm_buf_append_name(chip, &buf, options->keyhandle, NULL); + rc =3D tpm_buf_append_name(chip, &buf, options->keyhandle, parent_name, + parent_name_size); if (rc) goto out; =20 @@ -355,21 +364,25 @@ int tpm2_seal_trusted(struct tpm_chip *chip, } =20 /** - * tpm2_load_cmd() - execute a TPM2_Load command - * - * @chip: TPM chip to use - * @payload: the key data in clear and encrypted form - * @options: authentication values and other options - * @blob_handle: returned blob handle + * tpm2_load_cmd() - Execute TPM2_Load + * @chip: TPM chip to use. + * @payload: Key data in clear text. + * @options: Trusted key options. + * @parent_name: A cryptographic name, i.e. a TPMT_HA blob, of the + * parent key. + * @blob: The decoded payload for the key. + * @blob_handle: On success, will contain handle to the loaded keyedhash + * blob. * - * Return: 0 on success. - * -E2BIG on wrong payload size. - * -EPERM on tpm error status. - * < 0 error from tpm_send. + * Return -E2BIG when the blob size is too small for all the data. + * Returns tpm_transmit_cmd() error codes when either TPM2_Load fails. */ static int tpm2_load_cmd(struct tpm_chip *chip, struct trusted_key_payload *payload, struct trusted_key_options *options, + u8 *parent_name, + u16 parent_name_size, + const u8 *blob, u32 *blob_handle) { u8 *blob_ref __free(kfree) =3D NULL; @@ -377,27 +390,13 @@ static int tpm2_load_cmd(struct tpm_chip *chip, unsigned int private_len; unsigned int public_len; unsigned int blob_len; - u8 *blob, *pub; + const u8 *pub; int rc; u32 attrs; =20 - rc =3D tpm2_key_decode(payload, options, &blob); - if (rc) { - /* old form */ - blob =3D payload->blob; - payload->old_format =3D 1; - } else { - /* Bind for cleanup: */ - blob_ref =3D blob; - } - - /* new format carries keyhandle but old format doesn't */ - if (!options->keyhandle) - return -EINVAL; - /* must be big enough for at least the two be16 size counts */ if (payload->blob_len < 4) - return -EINVAL; + return -E2BIG; =20 private_len =3D get_unaligned_be16(blob); =20 @@ -433,7 +432,8 @@ static int tpm2_load_cmd(struct tpm_chip *chip, return rc; } =20 - rc =3D tpm_buf_append_name(chip, &buf, options->keyhandle, NULL); + rc =3D tpm_buf_append_name(chip, &buf, options->keyhandle, parent_name, + parent_name_size); if (rc) goto out; =20 @@ -465,20 +465,23 @@ static int tpm2_load_cmd(struct tpm_chip *chip, } =20 /** - * tpm2_unseal_cmd() - execute a TPM2_Unload command + * tpm2_unseal_cmd() - Execute TPM2_Unload * - * @chip: TPM chip to use - * @payload: the key data in clear and encrypted form - * @options: authentication values and other options - * @blob_handle: blob handle + * @chip: TPM chip to use + * @payload: Key data in clear text. + * @options: Trusted key options. + * @parent_name: A cryptographic name, i.e. a TPMT_HA blob, of the + * parent key. + * @blob_handle: Handle to the loaded keyedhash blob. * - * Return: 0 on success - * -EPERM on tpm error status - * < 0 error from tpm_send + * Return -E2BIG when the blob size is too small for all the data. + * Returns tpm_transmit_cmd() error codes when either TPM2_Load fails. */ static int tpm2_unseal_cmd(struct tpm_chip *chip, struct trusted_key_payload *payload, struct trusted_key_options *options, + u8 *parent_name, + u16 parent_name_size, u32 blob_handle) { struct tpm_header *head; @@ -498,7 +501,8 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip, return rc; } =20 - rc =3D tpm_buf_append_name(chip, &buf, options->keyhandle, NULL); + rc =3D tpm_buf_append_name(chip, &buf, options->keyhandle, parent_name, + parent_name_size); if (rc) goto out; =20 @@ -573,30 +577,60 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip, } =20 /** - * tpm2_unseal_trusted() - unseal the payload of a trusted key + * tpm2_unseal_trusted() - Unseal a trusted key + * @chip: TPM chip to use. + * @payload: Key data in clear text. + * @options: Trusted key options. * - * @chip: TPM chip to use - * @payload: the key data in clear and encrypted form - * @options: authentication values and other options - * - * Return: Same as with tpm_send. + * Return -E2BIG when the blob size is too small for all the data. + * Return -EINVAL when parent's key handle has not been set. + * Returns tpm_transmit_cmd() error codes when either TPM2_Load or TPM2_Un= seal + * fails. */ int tpm2_unseal_trusted(struct tpm_chip *chip, struct trusted_key_payload *payload, struct trusted_key_options *options) { + u8 *blob_ref __free(kfree) =3D NULL; + u8 parent_name[2 + SHA512_DIGEST_SIZE]; + u16 parent_name_size; u32 blob_handle; + u8 *blob; int rc; =20 + /* + * Try to decode the provided blob as an ASN.1 blob. Assume that the + * blob is in the legacy format if decoding does not end successfully. + */ + rc =3D tpm2_key_decode(payload, options, &blob); + if (rc) { + blob =3D payload->blob; + payload->old_format =3D 1; + } else { + blob_ref =3D blob; + } + + if (!options->keyhandle) + return -EINVAL; + rc =3D tpm_try_get_ops(chip); if (rc) return rc; =20 - rc =3D tpm2_load_cmd(chip, payload, options, &blob_handle); + rc =3D tpm2_read_public(chip, options->keyhandle, parent_name); + if (rc < 0) + goto out; + + parent_name_size =3D rc; + + rc =3D tpm2_load_cmd(chip, payload, options, parent_name, + parent_name_size, blob, &blob_handle); if (rc) goto out; =20 - rc =3D tpm2_unseal_cmd(chip, payload, options, blob_handle); + rc =3D tpm2_unseal_cmd(chip, payload, options, parent_name, + parent_name_size, blob_handle); + tpm2_flush_context(chip, blob_handle); =20 out: --=20 2.52.0 From nobody Fri Dec 19 16:17:57 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B75D21E8836; Fri, 5 Dec 2025 03:02:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764903748; cv=none; b=KGi0RD75V9g5zmUijqPFz1OmNS5L4EmpopPDYy6L9iiUr9bOU58SEXjX5b4LbLTK4Gy5gQ6edhY8XYc597rtfK12PfsrNtdgreT8PJSKMIxZhdkeX2PGp+A1Kt4wQUL+DFeCqaPL0isSX8k0F/KzHA0nvy4pA2n5g+d42Ir9c6s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764903748; c=relaxed/simple; bh=MjfFO/hzhMOZPTON5UBTvntl/aep/bQ6IYzfbUe9njw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=OlrI1gyue3RSjhG/4jnvvaqkR7JMJhSYCvgBDORbLI1GIkkWpLVMq2begSqvD4JSMIzlAcJ27SH2F5kLynb04ZUGK9yxNW6qnZ/D6bCe1T8putVOGIjEm3zTWYe8ARyP18E7vAGwzQ3L8Xx4lln8IMDx2c3rrlpB4f1ZjsayDQI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=hphsbwfx; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="hphsbwfx" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 07396C4CEFB; Fri, 5 Dec 2025 03:02:27 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1764903748; bh=MjfFO/hzhMOZPTON5UBTvntl/aep/bQ6IYzfbUe9njw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=hphsbwfx5rRVNgXWzQYH/AAVQEosIOgRCL9RjTfVfUTQx1Rpgt4muLCqhTsk6TD6t 8m6u3uC92DF0/91EaolMi9j4z/g+AdOsMqzWq/q7+QLntkWRJWl7Zv2984bp4SbLGM pDUGV5gktTUSKZp2s3Oywy/e8JTJ4udhQPBZYX6Ql3AHbswBbTziH2Ta6MUcgC+2uy OnDGz1uBH6pY63d3WftDXw7vROHEDyeSkbeDyEK+QdYHWucoN9gM5xgbdIIgonLiso Nji3ZVbYg3bF3ZvmeqB6OQtLVGIuvsKITgHHBpX0h0zymiiCfaxeuHlVgzac66/Rsc rUWoCvBTtd9Tg== From: Jarkko Sakkinen To: linux-integrity@vger.kernel.org Cc: Jarkko Sakkinen , Peter Huewe , Jason Gunthorpe , James Bottomley , Mimi Zohar , David Howells , Paul Moore , James Morris , "Serge E. Hallyn" , linux-kernel@vger.kernel.org (open list), keyrings@vger.kernel.org (open list:KEYS-TRUSTED), linux-security-module@vger.kernel.org (open list:SECURITY SUBSYSTEM) Subject: [PATCH v2 2/2] KEYS: trusted: Store parent's name to the encoded keys Date: Fri, 5 Dec 2025 05:02:05 +0200 Message-ID: <20251205030205.140842-3-jarkko@kernel.org> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20251205030205.140842-1-jarkko@kernel.org> References: <20251205030205.140842-1-jarkko@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Extend TPMKey ASN.1 speciication [1] with an optional 'parentName' attribute containing TPM name of the parent key (in other words, TPMT_HA blob). The life-cycle for trusted keys will now proceed as follows: 1. Encode parent's name to the 'paretName' during tpm2_key_encode(). 2. During tpm2_unseal_trusted, read parent's name from 'parentName'. When the attribute is not available, fallback on doing tpm2_read_public(). In other words, in the common (i.e., not loading a legacy key blob), tpm2_read_public() will now only happen at the time when a key is first created. [1] https://www.hansenpartnership.com/draft-bottomley-tpm2-keys.txt Signed-off-by: Jarkko Sakkinen --- v2: - A new patch. --- security/keys/trusted-keys/tpm2key.asn1 | 17 +++- security/keys/trusted-keys/trusted_tpm2.c | 97 ++++++++++++++++------- 2 files changed, 84 insertions(+), 30 deletions(-) diff --git a/security/keys/trusted-keys/tpm2key.asn1 b/security/keys/truste= d-keys/tpm2key.asn1 index f57f869ad600..080f0e399982 100644 --- a/security/keys/trusted-keys/tpm2key.asn1 +++ b/security/keys/trusted-keys/tpm2key.asn1 @@ -1,11 +1,26 @@ --- --- ASN.1 for TPM 2.0 keys --- +TPMPolicy ::=3D SEQUENCE { + commandCode [0] EXPLICIT INTEGER, + commandPolicy [1] EXPLICIT OCTET STRING +} + +TPMAuthPolicy ::=3D SEQUENCE { + name [0] EXPLICIT UTF8String OPTIONAL, + policy [1] EXPLICIT SEQUENCE OF TPMPolicy +} =20 TPMKey ::=3D SEQUENCE { type OBJECT IDENTIFIER ({tpm2_key_type}), emptyAuth [0] EXPLICIT BOOLEAN OPTIONAL, + policy [1] EXPLICIT SEQUENCE OF TPMPolicy OPTIONAL, + secret [2] EXPLICIT OCTET STRING OPTIONAL, + authPolicy [3] EXPLICIT SEQUENCE OF TPMAuthPolicy OPTIONAL, + description [4] EXPLICIT UTF8String OPTIONAL, + rsaParent [5] EXPLICIT BOOLEAN OPTIONAL, + parentName [6] EXPLICIT OCTET STRING ({tpm2_key_parent_name}), parent INTEGER ({tpm2_key_parent}), pubkey OCTET STRING ({tpm2_key_pub}), privkey OCTET STRING ({tpm2_key_priv}) - } +} diff --git a/security/keys/trusted-keys/trusted_tpm2.c b/security/keys/trus= ted-keys/trusted_tpm2.c index 88bafbcc011a..3608dc9f7fa4 100644 --- a/security/keys/trusted-keys/trusted_tpm2.c +++ b/security/keys/trusted-keys/trusted_tpm2.c @@ -20,16 +20,26 @@ =20 static u32 tpm2key_oid[] =3D { 2, 23, 133, 10, 1, 5 }; =20 +enum tpm_key_tag { + TPM_KEY_TAG_EMPTY_AUTH =3D 0, + TPM_KEY_TAG_POLICY =3D 1, + TPM_KEY_TAG_SECRET =3D 2, + TPM_KEY_TAG_AUTH_POLICY =3D 3, + TPM_KEY_TAG_DESCRIPTION =3D 4, + TPM_KEY_TAG_RSA_PARENT =3D 5, + TPM_KEY_TAG_PARENT_NAME =3D 6, +}; + static int tpm2_key_encode(struct trusted_key_payload *payload, struct trusted_key_options *options, - u8 *src, u32 len) + u8 *src, u32 len, u8 *parent_name, + u16 parent_name_size) { const int SCRATCH_SIZE =3D PAGE_SIZE; - u8 *scratch =3D kmalloc(SCRATCH_SIZE, GFP_KERNEL); - u8 *work =3D scratch, *work1; - u8 *end_work =3D scratch + SCRATCH_SIZE; - u8 *priv, *pub; + u8 *end_work, *name_end; u16 priv_len, pub_len; + u8 *work, *work1; + u8 *priv, *pub; int ret; =20 priv_len =3D get_unaligned_be16(src) + 2; @@ -40,23 +50,41 @@ static int tpm2_key_encode(struct trusted_key_payload *= payload, pub_len =3D get_unaligned_be16(src) + 2; pub =3D src; =20 + u8 *scratch __free(kfree) =3D kmalloc(SCRATCH_SIZE, GFP_KERNEL); if (!scratch) return -ENOMEM; =20 + work =3D scratch; + end_work =3D scratch + SCRATCH_SIZE; + work =3D asn1_encode_oid(work, end_work, tpm2key_oid, asn1_oid_len(tpm2key_oid)); =20 if (options->blobauth_len =3D=3D 0) { - unsigned char bool[3], *w =3D bool; - /* tag 0 is emptyAuth */ - w =3D asn1_encode_boolean(w, w + sizeof(bool), true); - if (WARN(IS_ERR(w), "BUG: Boolean failed to encode")) { - ret =3D PTR_ERR(w); - goto err; + u8 *bool_end; + u8 bool[3]; + + bool_end =3D asn1_encode_boolean(&bool[0], &bool[sizeof(bool)], + true); + if (IS_ERR(bool_end)) { + pr_err("BUG: Boolean failed to encode\n"); + return PTR_ERR(bool_end); } - work =3D asn1_encode_tag(work, end_work, 0, bool, w - bool); + + work =3D asn1_encode_tag(work, end_work, TPM_KEY_TAG_EMPTY_AUTH, + bool, bool_end - bool); } =20 + u8 *name_encoded __free(kfree) =3D kmalloc(SCRATCH_SIZE, GFP_KERNEL); + if (!name_encoded) + return -ENOMEM; + + name_end =3D asn1_encode_octet_string(&name_encoded[0], + &name_encoded[SCRATCH_SIZE], + parent_name, parent_name_size); + work =3D asn1_encode_tag(work, end_work, TPM_KEY_TAG_PARENT_NAME, + name_encoded, name_end - name_encoded); + /* * Assume both octet strings will encode to a 2 byte definite length * @@ -65,8 +93,7 @@ static int tpm2_key_encode(struct trusted_key_payload *pa= yload, */ if (WARN(work - scratch + pub_len + priv_len + 14 > SCRATCH_SIZE, "BUG: scratch buffer is too small")) { - ret =3D -EINVAL; - goto err; + return -EINVAL; } =20 work =3D asn1_encode_integer(work, end_work, options->keyhandle); @@ -79,15 +106,10 @@ static int tpm2_key_encode(struct trusted_key_payload = *payload, if (IS_ERR(work1)) { ret =3D PTR_ERR(work1); pr_err("BUG: ASN.1 encoder failed with %d\n", ret); - goto err; + return ret; } =20 - kfree(scratch); return work1 - payload->blob; - -err: - kfree(scratch); - return ret; } =20 struct tpm2_key_context { @@ -96,11 +118,13 @@ struct tpm2_key_context { u32 pub_len; const u8 *priv; u32 priv_len; + const u8 *name; + u32 name_len; }; =20 static int tpm2_key_decode(struct trusted_key_payload *payload, struct trusted_key_options *options, - u8 **buf) + u8 **buf, u8 *parent_name, u16 *parent_name_size) { int ret; struct tpm2_key_context ctx; @@ -127,6 +151,8 @@ static int tpm2_key_decode(struct trusted_key_payload *= payload, blob +=3D ctx.priv_len; =20 memcpy(blob, ctx.pub, ctx.pub_len); + memcpy(parent_name, ctx.name, ctx.name_len); + *parent_name_size =3D ctx.name_len; =20 return 0; } @@ -190,6 +216,16 @@ int tpm2_key_priv(void *context, size_t hdrlen, return 0; } =20 +int tpm2_key_parent_name(void *context, size_t hdrlen, unsigned char tag, + const void *value, size_t vlen) +{ + struct tpm2_key_context *ctx =3D context; + + ctx->name =3D value; + ctx->name_len =3D vlen; + + return 0; +} /** * tpm2_buf_append_auth() - append TPMS_AUTH_COMMAND to the buffer. * @@ -347,7 +383,8 @@ int tpm2_seal_trusted(struct tpm_chip *chip, goto out; } =20 - blob_len =3D tpm2_key_encode(payload, options, &buf.data[offset], blob_le= n); + blob_len =3D tpm2_key_encode(payload, options, &buf.data[offset], + blob_len, parent_name, parent_name_size); if (blob_len < 0) rc =3D blob_len; =20 @@ -602,7 +639,7 @@ int tpm2_unseal_trusted(struct tpm_chip *chip, * Try to decode the provided blob as an ASN.1 blob. Assume that the * blob is in the legacy format if decoding does not end successfully. */ - rc =3D tpm2_key_decode(payload, options, &blob); + rc =3D tpm2_key_decode(payload, options, &blob, &parent_name[0], &parent_= name_size); if (rc) { blob =3D payload->blob; payload->old_format =3D 1; @@ -613,16 +650,18 @@ int tpm2_unseal_trusted(struct tpm_chip *chip, if (!options->keyhandle) return -EINVAL; =20 + if (!parent_name_size) { + rc =3D tpm2_read_public(chip, options->keyhandle, parent_name); + if (rc < 0) + goto out; + + parent_name_size =3D rc; + } + rc =3D tpm_try_get_ops(chip); if (rc) return rc; =20 - rc =3D tpm2_read_public(chip, options->keyhandle, parent_name); - if (rc < 0) - goto out; - - parent_name_size =3D rc; - rc =3D tpm2_load_cmd(chip, payload, options, parent_name, parent_name_size, blob, &blob_handle); if (rc) --=20 2.52.0