Linux-NVME Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Marco Baffo <marco@mandelbit.com>
To: linux-crypto@vger.kernel.org
Cc: herbert@gondor.apana.org.au, davem@davemloft.net,
	ebiggers@kernel.org, Jason@zx2c4.com, ardb@kernel.org,
	tytso@mit.edu, jaegeuk@kernel.org, linux-fscrypt@vger.kernel.org,
	kbusch@kernel.org, axboe@kernel.dk, hch@lst.de, sagi@grimberg.me,
	hare@suse.de, linux-nvme@lists.infradead.org,
	andrew+netdev@lunn.ch, edumazet@google.com, kuba@kernel.org,
	pabeni@redhat.com, antonio@openvpn.net, sd@queasysnail.net,
	linux-kernel@vger.kernel.org, Marco Baffo <marco@mandelbit.com>
Subject: [PATCH 4/5] nvme-auth: use HKDF library functions for TLS PSK derivation
Date: Tue, 21 Jul 2026 16:06:43 +0200	[thread overview]
Message-ID: <20260721140644.780006-5-marco@mandelbit.com> (raw)
In-Reply-To: <20260721140644.780006-1-marco@mandelbit.com>

NVMe currently implements HKDF locally in nvme_auth_derive_tls_psk()
and allocates a temporary buffer for the HKDF-Expand input. Use the
common SHA-256 and SHA-384 HKDF helpers instead.

Pass the HkdfLabel fields as separate info segments, eliminating the
temporary allocation and its failure path.

The derived keys are unchanged. The segments are processed as if
concatenated, the expand counter byte is appended by the helper, and
the empty salt is equivalent to the previous digest-sized all-zero
salt after HMAC key padding.

Signed-off-by: Marco Baffo <marco@mandelbit.com>
---
 drivers/nvme/common/auth.c | 120 +++++++++++++++++++++----------------
 1 file changed, 68 insertions(+), 52 deletions(-)

diff --git a/drivers/nvme/common/auth.c b/drivers/nvme/common/auth.c
index 77f1d22512f8..b44922dd1cf6 100644
--- a/drivers/nvme/common/auth.c
+++ b/drivers/nvme/common/auth.c
@@ -10,6 +10,7 @@
 #include <linux/scatterlist.h>
 #include <linux/unaligned.h>
 #include <crypto/dh.h>
+#include <crypto/hkdf.h>
 #include <crypto/sha2.h>
 #include <linux/nvme.h>
 #include <linux/nvme-auth.h>
@@ -691,14 +692,19 @@ EXPORT_SYMBOL_GPL(nvme_auth_generate_digest);
 int nvme_auth_derive_tls_psk(int hmac_id, const u8 *psk, size_t psk_len,
 			     const char *psk_digest, u8 **ret_psk)
 {
-	static const u8 default_salt[NVME_AUTH_MAX_DIGEST_SIZE];
 	static const char label[] = "tls13 nvme-tls-psk";
-	const size_t label_len = sizeof(label) - 1;
-	u8 prk[NVME_AUTH_MAX_DIGEST_SIZE];
-	size_t hash_len, ctx_len;
-	u8 *hmac_data = NULL, *tls_key;
-	size_t i;
-	int ret;
+	const u8 label_len = sizeof(label) - 1;
+	union {
+		struct hmac_sha256_key sha256;
+		struct hmac_sha384_key sha384;
+	} prk;
+	struct hkdf_seg info[6];
+	size_t hash_len;
+	u8 output_len[2];
+	u8 ctx_len;
+	char ctx_prefix[4];
+	size_t digest_len;
+	u8 *tls_key;
 
 	hash_len = nvme_auth_hmac_hash_len(hmac_id);
 	if (hash_len == 0) {
@@ -717,64 +723,74 @@ int nvme_auth_derive_tls_psk(int hmac_id, const u8 *psk, size_t psk_len,
 		return -EINVAL;
 	}
 
-	/* HKDF-Extract */
-	ret = nvme_auth_hmac(hmac_id, default_salt, hash_len, psk, psk_len,
-			     prk);
-	if (ret)
-		goto out;
-
 	/*
-	 * HKDF-Expand-Label (RFC 8446 section 7.1), with output length equal to
-	 * the hash length (so only a single HMAC operation is needed)
+	 * HKDF-Expand-Label (RFC 8446 section 7.1).  The HKDF-Expand info
+	 * parameter is an encoded HkdfLabel containing the output length,
+	 * label, and context.
 	 */
 
-	hmac_data = kmalloc(/* output length */ 2 +
-			    /* label */ 1 + label_len +
-			    /* context (max) */ 1 + 3 + 1 + strlen(psk_digest) +
-			    /* counter */ 1,
-			    GFP_KERNEL);
-	if (!hmac_data) {
-		ret = -ENOMEM;
-		goto out;
-	}
 	/* output length */
-	i = 0;
-	hmac_data[i++] = hash_len >> 8;
-	hmac_data[i++] = hash_len;
+	output_len[0] = hash_len >> 8;
+	output_len[1] = hash_len;
+	info[0] = (struct hkdf_seg){
+		.data = output_len,
+		.len = sizeof(output_len),
+	};
 
 	/* label */
-	static_assert(label_len <= 255);
-	hmac_data[i] = label_len;
-	memcpy(&hmac_data[i + 1], label, label_len);
-	i += 1 + label_len;
+	static_assert(sizeof(label) - 1 <= 255);
+	info[1] = (struct hkdf_seg){
+		.data = &label_len,
+		.len = sizeof(label_len),
+	};
+	info[2] = (struct hkdf_seg){
+		.data = label,
+		.len = label_len,
+	};
 
 	/* context */
-	ctx_len = sprintf(&hmac_data[i + 1], "%02d %s", hmac_id, psk_digest);
-	if (ctx_len > 255) {
-		ret = -EINVAL;
-		goto out;
-	}
-	hmac_data[i] = ctx_len;
-	i += 1 + ctx_len;
+	digest_len = strlen(psk_digest);
+	if (digest_len > 255 - (sizeof(ctx_prefix) - 1))
+		return -EINVAL;
 
-	/* counter (this overwrites the NUL terminator written by sprintf) */
-	hmac_data[i++] = 1;
+	snprintf(ctx_prefix, sizeof(ctx_prefix), "%02d ", hmac_id);
+	ctx_len = sizeof(ctx_prefix) - 1 + digest_len;
+	info[3] = (struct hkdf_seg){
+		.data = &ctx_len,
+		.len = sizeof(ctx_len),
+	};
+	info[4] = (struct hkdf_seg){
+		.data = ctx_prefix,
+		.len = sizeof(ctx_prefix) - 1,
+	};
+	info[5] = (struct hkdf_seg){
+		.data = psk_digest,
+		.len = digest_len,
+	};
+
+	tls_key = kmalloc(psk_len, GFP_KERNEL);
+	if (!tls_key)
+		return -ENOMEM;
 
-	tls_key = kzalloc(psk_len, GFP_KERNEL);
-	if (!tls_key) {
-		ret = -ENOMEM;
-		goto out;
-	}
-	ret = nvme_auth_hmac(hmac_id, prk, hash_len, hmac_data, i, tls_key);
-	if (ret) {
+	switch (hmac_id) {
+	case NVME_AUTH_HASH_SHA256:
+		hkdf_sha256_extract(&prk.sha256, NULL, 0, psk, psk_len);
+		hkdf_sha256_expand(&prk.sha256, info, ARRAY_SIZE(info),
+				   tls_key, psk_len);
+		break;
+	case NVME_AUTH_HASH_SHA384:
+		hkdf_sha384_extract(&prk.sha384, NULL, 0, psk, psk_len);
+		hkdf_sha384_expand(&prk.sha384, info, ARRAY_SIZE(info),
+				   tls_key, psk_len);
+		break;
+	default:
+		WARN_ON_ONCE(1);
 		kfree_sensitive(tls_key);
-		goto out;
+		return -EINVAL;
 	}
+	memzero_explicit(&prk, sizeof(prk));
 	*ret_psk = tls_key;
-out:
-	kfree_sensitive(hmac_data);
-	memzero_explicit(prk, sizeof(prk));
-	return ret;
+	return 0;
 }
 EXPORT_SYMBOL_GPL(nvme_auth_derive_tls_psk);
 
-- 
2.43.0



  parent reply	other threads:[~2026-07-21 14:08 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-21 14:06 [PATCH 0/5] lib/crypto: add HKDF and convert fscrypt and NVMe Marco Baffo
2026-07-21 14:06 ` [PATCH 1/5] lib/crypto: add HKDF-SHA{256,384,512} Marco Baffo
2026-07-21 14:06 ` [PATCH 2/5] lib/crypto: tests: add HKDF KUnit tests Marco Baffo
2026-07-21 14:06 ` [PATCH 3/5] fscrypt: use HKDF library functions Marco Baffo
2026-07-21 14:06 ` Marco Baffo [this message]
2026-07-21 14:06 ` [RFC PATCH 5/5] ovpn: use HKDF library functions for epoch key derivation Marco Baffo
2026-07-21 15:06 ` [PATCH 0/5] lib/crypto: add HKDF and convert fscrypt and NVMe Eric Biggers

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260721140644.780006-5-marco@mandelbit.com \
    --to=marco@mandelbit.com \
    --cc=Jason@zx2c4.com \
    --cc=andrew+netdev@lunn.ch \
    --cc=antonio@openvpn.net \
    --cc=ardb@kernel.org \
    --cc=axboe@kernel.dk \
    --cc=davem@davemloft.net \
    --cc=ebiggers@kernel.org \
    --cc=edumazet@google.com \
    --cc=hare@suse.de \
    --cc=hch@lst.de \
    --cc=herbert@gondor.apana.org.au \
    --cc=jaegeuk@kernel.org \
    --cc=kbusch@kernel.org \
    --cc=kuba@kernel.org \
    --cc=linux-crypto@vger.kernel.org \
    --cc=linux-fscrypt@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-nvme@lists.infradead.org \
    --cc=pabeni@redhat.com \
    --cc=sagi@grimberg.me \
    --cc=sd@queasysnail.net \
    --cc=tytso@mit.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox