From nobody Sun Oct 5 14:30:39 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 738F328DB73; Fri, 1 Aug 2025 21:26:19 +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=1754083579; cv=none; b=Fv41IdACoMQRcneN8x93hgc1Aa0gYR/SzIAUU5UfiARapfZbtiCTyIrm8uwEH4h3mhSbIyjbDRZzAXnk4ZoxUL5gIrtV3hCXw/gCwGeR7cgb/vJnVsENkLvP5vtBVzYFKgt0IDVIkdQAlPKD5jwUrhe75caX7O/67zp23U7c2fY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754083579; c=relaxed/simple; bh=HZz9PkWbnw0uEcgraqNFNb8Xwl9CJAZ11ClEKIyhBfA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=TD/pg1WuWYFnLM/JBBUfFX71Va9V3wK2ggHdIizZcXHHXTvaQ5xe99AigkW9hmOaDtzyqD4UA8xzhdw7JlkNhFIYAeJmucI3QBGEA2RxpcEz3fHypZpUD5GMez66zvfajaus+iNQTYR+4upSfHefrei4GlDAn09B0fsakMN49lE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=gjc5EfQL; 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="gjc5EfQL" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B669FC4CEF9; Fri, 1 Aug 2025 21:26:18 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1754083579; bh=HZz9PkWbnw0uEcgraqNFNb8Xwl9CJAZ11ClEKIyhBfA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=gjc5EfQLF0Lavcpd6bo993onkSQIShmF9OxdhcwMeqioCFxuTRm6y+pbF0bsUG5Wp T+0ud3y4ui4iGXbVv1xuE4T6bUJ+G/XGScyMp886tqvEVHPa4FUvgwfhXga75cajkv ektCer2lWM+hW6rDYiPNWc8Ykb1sT/hbPbUxw5WmtGZMGfAhAcgxOUfdIdRxSVaUqf SPYg9w8beB39av38Hwxcvb/HEZGCpqd39miKSg210BcnYvXzfe13LhJK3TPWsEz5us XiCNVHtCeFxRHkJ8wptJQWCHv541Khr4YKgD8DlJ2gaKs//7fKYWd9UriyZrel9LOW a4uih01XtwRzg== From: Eric Biggers To: Peter Huewe , Jarkko Sakkinen , linux-integrity@vger.kernel.org Cc: Jason Gunthorpe , James Bottomley , linux-crypto@vger.kernel.org, linux-kernel@vger.kernel.org, Eric Biggers Subject: [PATCH v2 1/2] tpm: Compare HMAC values in constant time Date: Fri, 1 Aug 2025 14:24:21 -0700 Message-ID: <20250801212422.9590-2-ebiggers@kernel.org> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20250801212422.9590-1-ebiggers@kernel.org> References: <20250801212422.9590-1-ebiggers@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" In tpm_buf_check_hmac_response(), compare the HMAC values in constant time using crypto_memneq() instead of in variable time using memcmp(). This is worthwhile to follow best practices and to be consistent with MAC comparisons elsewhere in the kernel. However, in this driver the side channel seems to have been benign: the HMAC input data is guaranteed to always be unique, which makes the usual MAC forgery via timing side channel not possible. Specifically, the HMAC input data in tpm_buf_check_hmac_response() includes the "our_nonce" field, which was generated by the kernel earlier, remains under the control of the kernel, and is unique for each call to tpm_buf_check_hmac_response(). Signed-off-by: Eric Biggers --- drivers/char/tpm/Kconfig | 1 + drivers/char/tpm/tpm2-sessions.c | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index dddd702b2454a..f9d8a4e966867 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -31,10 +31,11 @@ config TCG_TPM2_HMAC bool "Use HMAC and encrypted transactions on the TPM bus" default X86_64 select CRYPTO_ECDH select CRYPTO_LIB_AESCFB select CRYPTO_LIB_SHA256 + select CRYPTO_LIB_UTILS help Setting this causes us to deploy a scheme which uses request and response HMACs in addition to encryption for communicating with the TPM to prevent or detect bus snooping and interposer attacks (see tpm-security.rst). Saying Y diff --git a/drivers/char/tpm/tpm2-sessions.c b/drivers/char/tpm/tpm2-sessi= ons.c index bdb119453dfbe..5fbd62ee50903 100644 --- a/drivers/char/tpm/tpm2-sessions.c +++ b/drivers/char/tpm/tpm2-sessions.c @@ -69,10 +69,11 @@ #include #include #include #include #include +#include =20 /* maximum number of names the TPM must remember for authorization */ #define AUTH_MAX_NAMES 3 =20 #define AES_KEY_BYTES AES_KEYSIZE_128 @@ -827,16 +828,15 @@ int tpm_buf_check_hmac_response(struct tpm_chip *chip= , struct tpm_buf *buf, sha256_update(&sctx, auth->our_nonce, sizeof(auth->our_nonce)); sha256_update(&sctx, &auth->attrs, 1); /* we're done with the rphash, so put our idea of the hmac there */ tpm2_hmac_final(&sctx, auth->session_key, sizeof(auth->session_key) + auth->passphrase_len, rphash); - if (memcmp(rphash, &buf->data[offset_s], SHA256_DIGEST_SIZE) =3D=3D 0) { - rc =3D 0; - } else { + if (crypto_memneq(rphash, &buf->data[offset_s], SHA256_DIGEST_SIZE)) { dev_err(&chip->dev, "TPM: HMAC check failed\n"); goto out; } + rc =3D 0; =20 /* now do response decryption */ if (auth->attrs & TPM2_SA_ENCRYPT) { /* need key and IV */ tpm2_KDFa(auth->session_key, SHA256_DIGEST_SIZE --=20 2.50.1 From nobody Sun Oct 5 14:30:39 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 A4B2D28DF3C; Fri, 1 Aug 2025 21:26:19 +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=1754083579; cv=none; b=lBdbFUgn+tUgUZ3/zAyvccwUlfVd8UTT54v/HZf2p8ru4GBGhAf28BvzSLcAXzERz7fyVzDej4L6yYEruU7nshPhELhO6awlJChYLjII7tfF3YbQAk443+NNkQu4nWG6/mE1ylVHdMF3yx8XEdhcUcS2IJgwpQAVtfSmfQfm3Qs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754083579; c=relaxed/simple; bh=FGVWbDM46/kQ8Qx86FzpGFJNytKs5fhu9qmULAUtmiQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=W18jL0dSB63GQi3teQhnAHh0qZc++w3J9R0dtHq1gyOL/DjXRZej6cIRZPYnmoNnru9PTslNrgClwzojfFHSkfRb3Tqpiil6EcvoDMlRFl4qnAXOyeul0R7za/E0OY2BNYkMhM7cqSdl+djZJ9Vi+btQ5f2b6pK7KZ69g2vPpg8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=aAA04uNB; 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="aAA04uNB" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 1D63FC4CEF4; Fri, 1 Aug 2025 21:26:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1754083579; bh=FGVWbDM46/kQ8Qx86FzpGFJNytKs5fhu9qmULAUtmiQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=aAA04uNBey7sQ0XVGfzni3JsLFmCU0J4cfoODJINtsNA3YWURaImVWIMY1e7CsUb8 UKZ/T5u1Y5RpvmPrXZiFnB8R0tt0G4phorQA1agypLhu5jgd8VguxCI0I1azwnHNaW REdG7WHhCiCxcjMEohqThx9bwi/q4+e8/y/kuRLgr79nzqyM+ONV7BqmLaFbv5OVm+ X8lAOAt967SAo19FDHsHvorKul1GFpz8FZJ8ROshDtJj/J1SkKgDJMtRU16jBiCfY4 OdhG70vKt6RH40DNYiA9+8h1N8JHR2cylp5omzzSnM87VKt4hxioRLfkhWrTxl6CUf ixM+4ODKVf5Rg== From: Eric Biggers To: Peter Huewe , Jarkko Sakkinen , linux-integrity@vger.kernel.org Cc: Jason Gunthorpe , James Bottomley , linux-crypto@vger.kernel.org, linux-kernel@vger.kernel.org, Eric Biggers Subject: [PATCH v2 2/2] tpm: Use HMAC-SHA256 library instead of open-coded HMAC Date: Fri, 1 Aug 2025 14:24:22 -0700 Message-ID: <20250801212422.9590-3-ebiggers@kernel.org> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20250801212422.9590-1-ebiggers@kernel.org> References: <20250801212422.9590-1-ebiggers@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" Now that there are easy-to-use HMAC-SHA256 library functions, use these in tpm2-sessions.c instead of open-coding the HMAC algorithm. Note that the new implementation correctly handles keys longer than 64 bytes (SHA256_BLOCK_SIZE), whereas the old implementation handled such keys incorrectly. But it doesn't appear that such keys were being used. Signed-off-by: Eric Biggers Reviewed-by: Jarkko Sakkinen --- drivers/char/tpm/tpm2-sessions.c | 98 +++++++++----------------------- 1 file changed, 27 insertions(+), 71 deletions(-) diff --git a/drivers/char/tpm/tpm2-sessions.c b/drivers/char/tpm/tpm2-sessi= ons.c index 5fbd62ee50903..6d03c224e6b21 100644 --- a/drivers/char/tpm/tpm2-sessions.c +++ b/drivers/char/tpm/tpm2-sessions.c @@ -67,12 +67,11 @@ #include #include #include #include #include -#include -#include +#include #include =20 /* maximum number of names the TPM must remember for authorization */ #define AUTH_MAX_NAMES 3 =20 @@ -383,55 +382,10 @@ EXPORT_SYMBOL_GPL(tpm_buf_append_hmac_session); #ifdef CONFIG_TCG_TPM2_HMAC =20 static int tpm2_create_primary(struct tpm_chip *chip, u32 hierarchy, u32 *handle, u8 *name); =20 -/* - * It turns out the crypto hmac(sha256) is hard for us to consume - * because it assumes a fixed key and the TPM seems to change the key - * on every operation, so we weld the hmac init and final functions in - * here to give it the same usage characteristics as a regular hash - */ -static void tpm2_hmac_init(struct sha256_ctx *sctx, u8 *key, u32 key_len) -{ - u8 pad[SHA256_BLOCK_SIZE]; - int i; - - sha256_init(sctx); - for (i =3D 0; i < sizeof(pad); i++) { - if (i < key_len) - pad[i] =3D key[i]; - else - pad[i] =3D 0; - pad[i] ^=3D HMAC_IPAD_VALUE; - } - sha256_update(sctx, pad, sizeof(pad)); -} - -static void tpm2_hmac_final(struct sha256_ctx *sctx, u8 *key, u32 key_len, - u8 *out) -{ - u8 pad[SHA256_BLOCK_SIZE]; - int i; - - for (i =3D 0; i < sizeof(pad); i++) { - if (i < key_len) - pad[i] =3D key[i]; - else - pad[i] =3D 0; - pad[i] ^=3D HMAC_OPAD_VALUE; - } - - /* collect the final hash; use out as temporary storage */ - sha256_final(sctx, out); - - sha256_init(sctx); - sha256_update(sctx, pad, sizeof(pad)); - sha256_update(sctx, out, SHA256_DIGEST_SIZE); - sha256_final(sctx, out); -} - /* * assume hash sha256 and nonces u, v of size SHA256_DIGEST_SIZE but * otherwise standard tpm2_KDFa. Note output is in bytes not bits. */ static void tpm2_KDFa(u8 *key, u32 key_len, const char *label, u8 *u, @@ -439,20 +393,20 @@ static void tpm2_KDFa(u8 *key, u32 key_len, const cha= r *label, u8 *u, { u32 counter =3D 1; const __be32 bits =3D cpu_to_be32(bytes * 8); =20 while (bytes > 0) { - struct sha256_ctx sctx; + struct hmac_sha256_ctx hctx; __be32 c =3D cpu_to_be32(counter); =20 - tpm2_hmac_init(&sctx, key, key_len); - sha256_update(&sctx, (u8 *)&c, sizeof(c)); - sha256_update(&sctx, label, strlen(label)+1); - sha256_update(&sctx, u, SHA256_DIGEST_SIZE); - sha256_update(&sctx, v, SHA256_DIGEST_SIZE); - sha256_update(&sctx, (u8 *)&bits, sizeof(bits)); - tpm2_hmac_final(&sctx, key, key_len, out); + hmac_sha256_init_usingrawkey(&hctx, key, key_len); + hmac_sha256_update(&hctx, (u8 *)&c, sizeof(c)); + hmac_sha256_update(&hctx, label, strlen(label) + 1); + hmac_sha256_update(&hctx, u, SHA256_DIGEST_SIZE); + hmac_sha256_update(&hctx, v, SHA256_DIGEST_SIZE); + hmac_sha256_update(&hctx, (u8 *)&bits, sizeof(bits)); + hmac_sha256_final(&hctx, out); =20 bytes -=3D SHA256_DIGEST_SIZE; counter++; out +=3D SHA256_DIGEST_SIZE; } @@ -592,10 +546,11 @@ void tpm_buf_fill_hmac_session(struct tpm_chip *chip,= struct tpm_buf *buf) off_t offset_s =3D TPM_HEADER_SIZE, offset_p; u8 *hmac =3D NULL; u32 attrs; u8 cphash[SHA256_DIGEST_SIZE]; struct sha256_ctx sctx; + struct hmac_sha256_ctx hctx; =20 if (!auth) return; =20 /* save the command code in BE format */ @@ -703,18 +658,18 @@ void tpm_buf_fill_hmac_session(struct tpm_chip *chip,= struct tpm_buf *buf) sha256_update(&sctx, &buf->data[offset_s], tpm_buf_length(buf) - offset_s); sha256_final(&sctx, cphash); =20 /* now calculate the hmac */ - tpm2_hmac_init(&sctx, auth->session_key, sizeof(auth->session_key) - + auth->passphrase_len); - sha256_update(&sctx, cphash, sizeof(cphash)); - sha256_update(&sctx, auth->our_nonce, sizeof(auth->our_nonce)); - sha256_update(&sctx, auth->tpm_nonce, sizeof(auth->tpm_nonce)); - sha256_update(&sctx, &auth->attrs, 1); - tpm2_hmac_final(&sctx, auth->session_key, sizeof(auth->session_key) - + auth->passphrase_len, hmac); + hmac_sha256_init_usingrawkey(&hctx, auth->session_key, + sizeof(auth->session_key) + + auth->passphrase_len); + hmac_sha256_update(&hctx, cphash, sizeof(cphash)); + hmac_sha256_update(&hctx, auth->our_nonce, sizeof(auth->our_nonce)); + hmac_sha256_update(&hctx, auth->tpm_nonce, sizeof(auth->tpm_nonce)); + hmac_sha256_update(&hctx, &auth->attrs, 1); + hmac_sha256_final(&hctx, hmac); } EXPORT_SYMBOL(tpm_buf_fill_hmac_session); =20 /** * tpm_buf_check_hmac_response() - check the TPM return HMAC for correctne= ss @@ -750,10 +705,11 @@ int tpm_buf_check_hmac_response(struct tpm_chip *chip= , struct tpm_buf *buf, struct tpm2_auth *auth =3D chip->auth; off_t offset_s, offset_p; u8 rphash[SHA256_DIGEST_SIZE]; u32 attrs, cc; struct sha256_ctx sctx; + struct hmac_sha256_ctx hctx; u16 tag =3D be16_to_cpu(head->tag); int parm_len, len, i, handles; =20 if (!auth) return rc; @@ -819,19 +775,19 @@ int tpm_buf_check_hmac_response(struct tpm_chip *chip= , struct tpm_buf *buf, sha256_update(&sctx, (u8 *)&auth->ordinal, sizeof(auth->ordinal)); sha256_update(&sctx, &buf->data[offset_p], parm_len); sha256_final(&sctx, rphash); =20 /* now calculate the hmac */ - tpm2_hmac_init(&sctx, auth->session_key, sizeof(auth->session_key) - + auth->passphrase_len); - sha256_update(&sctx, rphash, sizeof(rphash)); - sha256_update(&sctx, auth->tpm_nonce, sizeof(auth->tpm_nonce)); - sha256_update(&sctx, auth->our_nonce, sizeof(auth->our_nonce)); - sha256_update(&sctx, &auth->attrs, 1); + hmac_sha256_init_usingrawkey(&hctx, auth->session_key, + sizeof(auth->session_key) + + auth->passphrase_len); + hmac_sha256_update(&hctx, rphash, sizeof(rphash)); + hmac_sha256_update(&hctx, auth->tpm_nonce, sizeof(auth->tpm_nonce)); + hmac_sha256_update(&hctx, auth->our_nonce, sizeof(auth->our_nonce)); + hmac_sha256_update(&hctx, &auth->attrs, 1); /* we're done with the rphash, so put our idea of the hmac there */ - tpm2_hmac_final(&sctx, auth->session_key, sizeof(auth->session_key) - + auth->passphrase_len, rphash); + hmac_sha256_final(&hctx, rphash); if (crypto_memneq(rphash, &buf->data[offset_s], SHA256_DIGEST_SIZE)) { dev_err(&chip->dev, "TPM: HMAC check failed\n"); goto out; } rc =3D 0; --=20 2.50.1