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 2/5] lib/crypto: tests: add HKDF KUnit tests
Date: Tue, 21 Jul 2026 16:06:41 +0200	[thread overview]
Message-ID: <20260721140644.780006-3-marco@mandelbit.com> (raw)
In-Reply-To: <20260721140644.780006-1-marco@mandelbit.com>

Add KUnit tests for the HKDF-SHA{256,384,512} helpers using the
RFC 5869 SHA-256 vectors and SHA-384 and SHA-512 vectors generated
with "openssl kdf" from the same inputs. Also test empty salt and
info, multi-block output, and segmented info.

Signed-off-by: Marco Baffo <marco@mandelbit.com>
---
 lib/crypto/.kunitconfig       |   1 +
 lib/crypto/tests/Kconfig      |   8 +
 lib/crypto/tests/Makefile     |   1 +
 lib/crypto/tests/hkdf_kunit.c | 276 ++++++++++++++++++++++++++++++++++
 4 files changed, 286 insertions(+)
 create mode 100644 lib/crypto/tests/hkdf_kunit.c

diff --git a/lib/crypto/.kunitconfig b/lib/crypto/.kunitconfig
index 3efc854a2c08..82739358aa44 100644
--- a/lib/crypto/.kunitconfig
+++ b/lib/crypto/.kunitconfig
@@ -8,6 +8,7 @@ CONFIG_CRYPTO_LIB_BLAKE2S_KUNIT_TEST=y
 CONFIG_CRYPTO_LIB_CHACHA20POLY1305_KUNIT_TEST=y
 CONFIG_CRYPTO_LIB_CURVE25519_KUNIT_TEST=y
 CONFIG_CRYPTO_LIB_GHASH_KUNIT_TEST=y
+CONFIG_CRYPTO_LIB_HKDF_KUNIT_TEST=y
 CONFIG_CRYPTO_LIB_MD5_KUNIT_TEST=y
 CONFIG_CRYPTO_LIB_MLDSA_KUNIT_TEST=y
 CONFIG_CRYPTO_LIB_NH_KUNIT_TEST=y
diff --git a/lib/crypto/tests/Kconfig b/lib/crypto/tests/Kconfig
index bc084dde424f..900e5d3afd00 100644
--- a/lib/crypto/tests/Kconfig
+++ b/lib/crypto/tests/Kconfig
@@ -52,6 +52,14 @@ config CRYPTO_LIB_GHASH_KUNIT_TEST
 	help
 	  KUnit tests for the GHASH library functions.
 
+config CRYPTO_LIB_HKDF_KUNIT_TEST
+	tristate "KUnit tests for HKDF" if !KUNIT_ALL_TESTS
+	depends on KUNIT && CRYPTO_LIB_SHA256 && CRYPTO_LIB_SHA512
+	default KUNIT_ALL_TESTS
+	help
+	  KUnit tests for the HKDF-SHA256, HKDF-SHA384, and HKDF-SHA512 key
+	  derivation functions.
+
 config CRYPTO_LIB_MD5_KUNIT_TEST
 	tristate "KUnit tests for MD5" if !KUNIT_ALL_TESTS
 	depends on KUNIT && CRYPTO_LIB_MD5
diff --git a/lib/crypto/tests/Makefile b/lib/crypto/tests/Makefile
index a739413500b6..15a2f9b54458 100644
--- a/lib/crypto/tests/Makefile
+++ b/lib/crypto/tests/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_CRYPTO_LIB_BLAKE2S_KUNIT_TEST) += blake2s_kunit.o
 obj-$(CONFIG_CRYPTO_LIB_CHACHA20POLY1305_KUNIT_TEST) += chacha20poly1305_kunit.o
 obj-$(CONFIG_CRYPTO_LIB_CURVE25519_KUNIT_TEST) += curve25519_kunit.o
 obj-$(CONFIG_CRYPTO_LIB_GHASH_KUNIT_TEST) += ghash_kunit.o
+obj-$(CONFIG_CRYPTO_LIB_HKDF_KUNIT_TEST) += hkdf_kunit.o
 obj-$(CONFIG_CRYPTO_LIB_MD5_KUNIT_TEST) += md5_kunit.o
 obj-$(CONFIG_CRYPTO_LIB_MLDSA_KUNIT_TEST) += mldsa_kunit.o
 obj-$(CONFIG_CRYPTO_LIB_NH_KUNIT_TEST) += nh_kunit.o
diff --git a/lib/crypto/tests/hkdf_kunit.c b/lib/crypto/tests/hkdf_kunit.c
new file mode 100644
index 000000000000..e8f65d761cc0
--- /dev/null
+++ b/lib/crypto/tests/hkdf_kunit.c
@@ -0,0 +1,276 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * KUnit tests for HKDF-SHA256, HKDF-SHA384, and HKDF-SHA512
+ *
+ * The HKDF-SHA256 test vectors are from RFC 5869 Appendix A. RFC 5869 does not
+ * provide SHA-384 or SHA-512 vectors, so those were generated with OpenSSL's
+ * "openssl kdf" command (available since OpenSSL 3.0) using the same inputs as
+ * the SHA-256 vectors.  See: https://docs.openssl.org/3.0/man1/openssl-kdf/
+ *
+ * For example, the SHA-384 vector was generated with:
+ *
+ * $ openssl kdf -keylen 42 -kdfopt mode:EXTRACT_AND_EXPAND \
+ *     -kdfopt digest:SHA384 \
+ *     -kdfopt hexkey:0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b \
+ *     -kdfopt hexsalt:000102030405060708090a0b0c \
+ *     -kdfopt hexinfo:f0f1f2f3f4f5f6f7f8f9 HKDF
+ */
+
+#include <crypto/hkdf.h>
+#include <kunit/test.h>
+
+#define RFC5869_A1_IKM_BYTE	0x0b
+#define RFC5869_A1_IKM_LEN	22
+#define RFC5869_A1_SALT_START	0x00
+#define RFC5869_A1_SALT_LEN	13
+#define RFC5869_A1_INFO_START	0xf0
+#define RFC5869_A1_INFO_LEN	10
+
+#define RFC5869_A2_IKM_START	0x00
+#define RFC5869_A2_IKM_LEN	80
+#define RFC5869_A2_SALT_START	0x60
+#define RFC5869_A2_SALT_LEN	80
+#define RFC5869_A2_INFO_START	0xb0
+#define RFC5869_A2_INFO_LEN	80
+
+#define SEGMENT_TEST_INFO_LEN	40
+#define SEGMENT_TEST_OKM_LEN	100
+
+/* RFC 5869 A.1: ikm = 22 x 0x0b, salt = 0x00..0x0c, info = 0xf0..0xf9 */
+static const u8 rfc5869_a1_okm[] = {
+	0x3c, 0xb2, 0x5f, 0x25, 0xfa, 0xac, 0xd5, 0x7a,
+	0x90, 0x43, 0x4f, 0x64, 0xd0, 0x36, 0x2f, 0x2a,
+	0x2d, 0x2d, 0x0a, 0x90, 0xcf, 0x1a, 0x5a, 0x4c,
+	0x5d, 0xb0, 0x2d, 0x56, 0xec, 0xc4, 0xc5, 0xbf,
+	0x34, 0x00, 0x72, 0x08, 0xd5, 0xb8, 0x87, 0x18,
+	0x58, 0x65
+};
+
+/* RFC 5869 A.2: ikm = 0x00..0x4f, salt = 0x60..0xaf, info = 0xb0..0xff */
+static const u8 rfc5869_a2_okm[] = {
+	0xb1, 0x1e, 0x39, 0x8d, 0xc8, 0x03, 0x27, 0xa1,
+	0xc8, 0xe7, 0xf7, 0x8c, 0x59, 0x6a, 0x49, 0x34,
+	0x4f, 0x01, 0x2e, 0xda, 0x2d, 0x4e, 0xfa, 0xd8,
+	0xa0, 0x50, 0xcc, 0x4c, 0x19, 0xaf, 0xa9, 0x7c,
+	0x59, 0x04, 0x5a, 0x99, 0xca, 0xc7, 0x82, 0x72,
+	0x71, 0xcb, 0x41, 0xc6, 0x5e, 0x59, 0x0e, 0x09,
+	0xda, 0x32, 0x75, 0x60, 0x0c, 0x2f, 0x09, 0xb8,
+	0x36, 0x77, 0x93, 0xa9, 0xac, 0xa3, 0xdb, 0x71,
+	0xcc, 0x30, 0xc5, 0x81, 0x79, 0xec, 0x3e, 0x87,
+	0xc1, 0x4c, 0x01, 0xd5, 0xc1, 0xf3, 0x43, 0x4f,
+	0x1d, 0x87
+};
+
+/* RFC 5869 A.3: ikm = 22 x 0x0b, zero-length salt and info */
+static const u8 rfc5869_a3_okm[] = {
+	0x8d, 0xa4, 0xe7, 0x75, 0xa5, 0x63, 0xc1, 0x8f,
+	0x71, 0x5f, 0x80, 0x2a, 0x06, 0x3c, 0x5a, 0x31,
+	0xb8, 0xa1, 0x1f, 0x5c, 0x5e, 0xe1, 0x87, 0x9e,
+	0xc3, 0x45, 0x4e, 0x5f, 0x3c, 0x73, 0x8d, 0x2d,
+	0x9d, 0x20, 0x13, 0x95, 0xfa, 0xa4, 0xb6, 0x1a,
+	0x96, 0xc8
+};
+
+/* HKDF-SHA384 with the RFC 5869 A.1 inputs */
+static const u8 hkdf_sha384_a1_okm[] = {
+	0x9b, 0x50, 0x97, 0xa8, 0x60, 0x38, 0xb8, 0x05,
+	0x30, 0x90, 0x76, 0xa4, 0x4b, 0x3a, 0x9f, 0x38,
+	0x06, 0x3e, 0x25, 0xb5, 0x16, 0xdc, 0xbf, 0x36,
+	0x9f, 0x39, 0x4c, 0xfa, 0xb4, 0x36, 0x85, 0xf7,
+	0x48, 0xb6, 0x45, 0x77, 0x63, 0xe4, 0xf0, 0x20,
+	0x4f, 0xc5
+};
+
+/* HKDF-SHA512 with the RFC 5869 A.1 inputs */
+static const u8 hkdf_sha512_a1_okm[] = {
+	0x83, 0x23, 0x90, 0x08, 0x6c, 0xda, 0x71, 0xfb,
+	0x47, 0x62, 0x5b, 0xb5, 0xce, 0xb1, 0x68, 0xe4,
+	0xc8, 0xe2, 0x6a, 0x1a, 0x16, 0xed, 0x34, 0xd9,
+	0xfc, 0x7f, 0xe9, 0x2c, 0x14, 0x81, 0x57, 0x93,
+	0x38, 0xda, 0x36, 0x2c, 0xb8, 0xd9, 0xf9, 0x25,
+	0xd7, 0xcb
+};
+
+/*
+ * HKDF-SHA512 with the RFC 5869 A.3 inputs and okm_len = 150, so that the
+ * output spans multiple blocks and ends with a partial block
+ */
+static const u8 hkdf_sha512_a3_okm[] = {
+	0xf5, 0xfa, 0x02, 0xb1, 0x82, 0x98, 0xa7, 0x2a,
+	0x8c, 0x23, 0x89, 0x8a, 0x87, 0x03, 0x47, 0x2c,
+	0x6e, 0xb1, 0x79, 0xdc, 0x20, 0x4c, 0x03, 0x42,
+	0x5c, 0x97, 0x0e, 0x3b, 0x16, 0x4b, 0xf9, 0x0f,
+	0xff, 0x22, 0xd0, 0x48, 0x36, 0xd0, 0xe2, 0x34,
+	0x3b, 0xac, 0xc4, 0xe7, 0xcb, 0x60, 0x45, 0xfa,
+	0xaa, 0x69, 0x8e, 0x0e, 0x3b, 0x3e, 0xb9, 0x13,
+	0x31, 0x30, 0x6d, 0xef, 0x1d, 0xb8, 0x31, 0x9e,
+	0x8a, 0x69, 0x9b, 0x5e, 0xe4, 0x5a, 0xb9, 0x93,
+	0x84, 0x7d, 0xc4, 0xdf, 0x75, 0xbd, 0xe0, 0x23,
+	0x69, 0x2c, 0x8c, 0x07, 0x10, 0xa6, 0x7a, 0x55,
+	0x12, 0x3f, 0x10, 0xa8, 0xb2, 0xd8, 0x32, 0x7f,
+	0x9e, 0xb1, 0x38, 0xda, 0x69, 0xd5, 0xbe, 0xa1,
+	0xe0, 0x9a, 0x39, 0xea, 0x99, 0xa3, 0x41, 0xc0,
+	0x0b, 0x2c, 0x9e, 0xe0, 0xd4, 0xba, 0x63, 0x21,
+	0x15, 0xae, 0xc5, 0x16, 0xbb, 0x71, 0xe9, 0x22,
+	0x7c, 0xb0, 0x0c, 0xa9, 0x8b, 0x7d, 0xfa, 0x8f,
+	0x1c, 0x7e, 0xca, 0x60, 0xc9, 0x31, 0x28, 0x1f,
+	0xa8, 0x5b, 0x87, 0x2f, 0x70, 0xb4
+};
+
+/*
+ * Utility function to initialize ikm/salt/info buffers.
+ * Fill 'buf' with 'len' consecutive byte values beginning with 'start'.
+ */
+static void fill_range(u8 *buf, size_t len, u8 start)
+{
+	for (size_t i = 0; i < len; i++)
+		buf[i] = start + i;
+}
+
+static void test_hkdf_sha256_rfc5869(struct kunit *test)
+{
+	struct hmac_sha256_key prk;
+	u8 ikm[RFC5869_A2_IKM_LEN];
+	u8 salt[RFC5869_A2_SALT_LEN];
+	u8 info[RFC5869_A2_INFO_LEN];
+	u8 okm[sizeof(rfc5869_a2_okm)];
+	struct hkdf_seg seg;
+
+	/* A.1: basic test case */
+	memset(ikm, RFC5869_A1_IKM_BYTE, RFC5869_A1_IKM_LEN);
+	fill_range(salt, RFC5869_A1_SALT_LEN, RFC5869_A1_SALT_START);
+	fill_range(info, RFC5869_A1_INFO_LEN, RFC5869_A1_INFO_START);
+	hkdf_sha256_extract(&prk, salt, RFC5869_A1_SALT_LEN,
+			    ikm, RFC5869_A1_IKM_LEN);
+	seg = (struct hkdf_seg){ .data = info, .len = RFC5869_A1_INFO_LEN };
+	hkdf_sha256_expand(&prk, &seg, 1, okm, sizeof(rfc5869_a1_okm));
+	KUNIT_EXPECT_MEMEQ_MSG(test, okm, rfc5869_a1_okm,
+			       sizeof(rfc5869_a1_okm), "RFC 5869 A.1");
+
+	/* A.2: longer inputs, multi-block output ending in a partial block */
+	fill_range(ikm, RFC5869_A2_IKM_LEN, RFC5869_A2_IKM_START);
+	fill_range(salt, RFC5869_A2_SALT_LEN, RFC5869_A2_SALT_START);
+	fill_range(info, RFC5869_A2_INFO_LEN, RFC5869_A2_INFO_START);
+	hkdf_sha256_extract(&prk, salt, RFC5869_A2_SALT_LEN,
+			    ikm, RFC5869_A2_IKM_LEN);
+	seg = (struct hkdf_seg){ .data = info, .len = RFC5869_A2_INFO_LEN };
+	hkdf_sha256_expand(&prk, &seg, 1, okm, sizeof(rfc5869_a2_okm));
+	KUNIT_EXPECT_MEMEQ_MSG(test, okm, rfc5869_a2_okm,
+			       sizeof(rfc5869_a2_okm), "RFC 5869 A.2");
+
+	/* A.3: zero-length salt and info */
+	memset(ikm, RFC5869_A1_IKM_BYTE, RFC5869_A1_IKM_LEN);
+	hkdf_sha256_extract(&prk, NULL, 0, ikm, RFC5869_A1_IKM_LEN);
+	hkdf_sha256_expand(&prk, NULL, 0, okm, sizeof(rfc5869_a3_okm));
+	KUNIT_EXPECT_MEMEQ_MSG(test, okm, rfc5869_a3_okm,
+			       sizeof(rfc5869_a3_okm),
+			       "RFC 5869 A.3 with NULL salt and info");
+
+	/* A.3 again, with a non-NULL empty salt and an empty info segment */
+	hkdf_sha256_extract(&prk, salt, 0, ikm, RFC5869_A1_IKM_LEN);
+	seg = (struct hkdf_seg){ .data = info, .len = 0 };
+	hkdf_sha256_expand(&prk, &seg, 1, okm, sizeof(rfc5869_a3_okm));
+	KUNIT_EXPECT_MEMEQ_MSG(test, okm, rfc5869_a3_okm,
+			       sizeof(rfc5869_a3_okm),
+			       "RFC 5869 A.3 with non-NULL empty salt and info");
+}
+
+static void test_hkdf_sha384_rfc5869_a1(struct kunit *test)
+{
+	struct hmac_sha384_key prk;
+	u8 ikm[RFC5869_A1_IKM_LEN];
+	u8 salt[RFC5869_A1_SALT_LEN];
+	u8 info[RFC5869_A1_INFO_LEN];
+	u8 okm[sizeof(hkdf_sha384_a1_okm)];
+	struct hkdf_seg seg;
+
+	memset(ikm, RFC5869_A1_IKM_BYTE, sizeof(ikm));
+	fill_range(salt, sizeof(salt), RFC5869_A1_SALT_START);
+	fill_range(info, sizeof(info), RFC5869_A1_INFO_START);
+	seg = (struct hkdf_seg){ .data = info, .len = sizeof(info) };
+	hkdf_sha384_extract(&prk, salt, sizeof(salt), ikm, sizeof(ikm));
+	hkdf_sha384_expand(&prk, &seg, 1, okm, sizeof(okm));
+	KUNIT_EXPECT_MEMEQ_MSG(test, okm, hkdf_sha384_a1_okm, sizeof(okm),
+			       "SHA-384 with RFC 5869 A.1 inputs");
+}
+
+static void test_hkdf_sha512_rfc5869_a1_a3(struct kunit *test)
+{
+	struct hmac_sha512_key prk;
+	u8 ikm[RFC5869_A1_IKM_LEN];
+	u8 salt[RFC5869_A1_SALT_LEN];
+	u8 info[RFC5869_A1_INFO_LEN];
+	u8 okm[sizeof(hkdf_sha512_a3_okm)];
+	struct hkdf_seg seg;
+
+	memset(ikm, RFC5869_A1_IKM_BYTE, sizeof(ikm));
+	fill_range(salt, sizeof(salt), RFC5869_A1_SALT_START);
+	fill_range(info, sizeof(info), RFC5869_A1_INFO_START);
+	seg = (struct hkdf_seg){ .data = info, .len = sizeof(info) };
+	hkdf_sha512_extract(&prk, salt, sizeof(salt), ikm, sizeof(ikm));
+	hkdf_sha512_expand(&prk, &seg, 1, okm, sizeof(hkdf_sha512_a1_okm));
+	KUNIT_EXPECT_MEMEQ_MSG(test, okm, hkdf_sha512_a1_okm,
+			       sizeof(hkdf_sha512_a1_okm),
+			       "SHA-512 with RFC 5869 A.1 inputs");
+
+	hkdf_sha512_extract(&prk, NULL, 0, ikm, sizeof(ikm));
+	hkdf_sha512_expand(&prk, NULL, 0, okm, sizeof(hkdf_sha512_a3_okm));
+	KUNIT_EXPECT_MEMEQ_MSG(test, okm, hkdf_sha512_a3_okm,
+			       sizeof(hkdf_sha512_a3_okm),
+			       "SHA-512 with RFC 5869 A.3 inputs and 150-byte OKM");
+}
+
+/* Test that splitting info into segments does not influence the output. */
+static void test_hkdf_expand_info_segments(struct kunit *test)
+{
+	struct hmac_sha512_key prk;
+	u8 ikm[RFC5869_A1_IKM_LEN];
+	u8 info[SEGMENT_TEST_INFO_LEN];
+	u8 okm_ref[SEGMENT_TEST_OKM_LEN];
+	u8 okm[SEGMENT_TEST_OKM_LEN];
+	struct hkdf_seg segs[sizeof(info)];
+
+	memset(ikm, RFC5869_A1_IKM_BYTE, sizeof(ikm));
+	fill_range(info, sizeof(info), 0x00);
+	hkdf_sha512_extract(&prk, NULL, 0, ikm, sizeof(ikm));
+
+	segs[0] = (struct hkdf_seg){ .data = info, .len = sizeof(info) };
+	hkdf_sha512_expand(&prk, segs, 1, okm_ref, sizeof(okm_ref));
+
+	/* every possible two-way split */
+	for (size_t split = 0; split <= sizeof(info); split++) {
+		segs[0] = (struct hkdf_seg){ .data = info, .len = split };
+		segs[1] = (struct hkdf_seg){ .data = &info[split],
+					     .len = sizeof(info) - split };
+		memset(okm, 0, sizeof(okm));
+		hkdf_sha512_expand(&prk, segs, 2, okm, sizeof(okm));
+		KUNIT_EXPECT_MEMEQ_MSG(test, okm, okm_ref, sizeof(okm),
+				       "failed for split=%zu", split);
+	}
+
+	/* one segment per byte */
+	for (size_t i = 0; i < sizeof(info); i++)
+		segs[i] = (struct hkdf_seg){ .data = &info[i], .len = 1 };
+	memset(okm, 0, sizeof(okm));
+	hkdf_sha512_expand(&prk, segs, sizeof(info), okm, sizeof(okm));
+	KUNIT_EXPECT_MEMEQ_MSG(test, okm, okm_ref, sizeof(okm),
+			       "one info segment per byte");
+}
+
+static struct kunit_case hkdf_test_cases[] = {
+	KUNIT_CASE(test_hkdf_sha256_rfc5869),
+	KUNIT_CASE(test_hkdf_sha384_rfc5869_a1),
+	KUNIT_CASE(test_hkdf_sha512_rfc5869_a1_a3),
+	KUNIT_CASE(test_hkdf_expand_info_segments),
+	{},
+};
+
+static struct kunit_suite hkdf_test_suite = {
+	.name = "hkdf",
+	.test_cases = hkdf_test_cases,
+};
+
+kunit_test_suite(hkdf_test_suite);
+
+MODULE_DESCRIPTION("KUnit tests for HKDF-SHA256, HKDF-SHA384, and HKDF-SHA512");
+MODULE_LICENSE("GPL");
-- 
2.43.0



  parent reply	other threads:[~2026-07-21 14:07 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 ` Marco Baffo [this message]
2026-07-21 14:06 ` [PATCH 3/5] fscrypt: use HKDF library functions Marco Baffo
2026-07-21 14:06 ` [PATCH 4/5] nvme-auth: use HKDF library functions for TLS PSK derivation Marco Baffo
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-3-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