crypto,nvme: fixup HKDF-Expand-Label implementation
Subsystems (2)
cover crypto,nvme: fixup HKDF-Expand-Label implementation
From: Hannes Reinecke <[email protected]>
As per RFC 8446 (TLS 1.3) the HKDF-Expand-Label function is using vectors for the 'label' and 'context' field, but defines these vectors as a string prefixed with the string length (in binary). The implementation in nvme is missing the length prefix which was causing interoperability issues with spec-conformant implementations.
This patchset adds a function 'hkdf_expand_label()' to correctly implement the HKDF-Expand-Label functionality and modifies the nvme driver to utilize this function instead of the open-coded implementation.
As usual, comments and reviews are welcome.
Chris Leech (1):
crypto: hkdf: add hkdf_expand_label()
Hannes Reinecke (1):
nvme-auth: use hkdf_expand_label()
crypto/hkdf.c | 55 ++++++++++++++++++++++++++++++++++++++ drivers/nvme/common/auth.c | 33 +++++++++-------------- include/crypto/hkdf.h | 4 +++ 3 files changed, 72 insertions(+), 20 deletions(-)
Signature · 1 line
2.43.0
PATCH 1/2 crypto: hkdf: add hkdf_expand_label()
From: Chris Leech <[email protected]>
Provide an implementation of RFC 8446 (TLS 1.3) HKDF-Expand-Label
--- crypto/hkdf.c | 55 +++++++++++++++++++++++++++++++++++++++++++ include/crypto/hkdf.h | 4 ++++ 2 files changed, 59 insertions(+)
crypto/hkdf.c +55 -0
@@ -11,6 +11,7 @@#include <crypto/sha2.h> #include <crypto/hkdf.h> #include <linux/module.h> +#include <linux/unaligned.h> /* * HKDF consists of two steps:
@@ -129,6 +130,60 @@ int hkdf_expand(struct crypto_shash *hmac_tfm, }EXPORT_SYMBOL_GPL (hkdf_expand); +/** +* hkdf_expand_label - HKDF-Expand-Label (RFC 8846 section 7.1) +* @hmac_tfm: hash context keyed with pseudorandom key +* @label: ASCII label without "tls13 " prefix +* @label_len: length of @label +* @context: context bytes +* @contextlen: length of @context +* @okm: output keying material +* @okmlen: length of @okm +* +* Build the TLS 1.3 HkdfLabel structure and invoke hkdf_expand(). +* +* Returns 0 on success with output keying material stored in @okm, +* or a negative errno value otherwise. +*/ +int hkdf_expand_label (struct crypto_shash *hmac_tfm, +const u8 *label,unsigned int labellen, +const u8 *context,unsigned int contextlen, +u8 *okm,unsigned int okmlen) +{ +int err; +u8 *info; +unsigned int infolen; +static const char tls13_prefix[] ="tls13 " ; +unsigned int prefixlen =sizeof (tls13_prefix) -1 ;/* exclude NUL */ + +if (WARN_ON (labellen > (255 - prefixlen))) +return -EINVAL ; +if (WARN_ON (contextlen >255 )) +return -EINVAL ; + + infolen =2 + (1 + prefixlen + labellen) + (1 + contextlen); + info =kzalloc (infolen,GFP_KERNEL ); +if (!info) +return -ENOMEM ; + +/* HkdfLabel.Length */ +put_unaligned_be16 (okmlen, info); + +/* HkdfLabel.Label */ + info[2 ] = prefixlen + labellen; +memcpy (info +3 , tls13_prefix, prefixlen); +memcpy (info +3 + prefixlen, label, labellen); + +/* HkdfLabel.Context */ + info[3 + prefixlen + labellen] = contextlen; +memcpy (info +4 + prefixlen + labellen, context, contextlen); + + err =hkdf_expand (hmac_tfm, info, infolen, okm, okmlen); +kfree_sensitive (info); +return err; +} +EXPORT_SYMBOL_GPL (hkdf_expand_label); +struct hkdf_testvec {const char *test;const u8 *ikm;
include/crypto/hkdf.h +4 -0
@@ -17,4 +17,8 @@ int hkdf_extract(struct crypto_shash *hmac_tfm, const u8 *ikm,int hkdf_expand (struct crypto_shash *hmac_tfm,const u8 *info,unsigned int infolen,u8 *okm,unsigned int okmlen); +int hkdf_expand_label (struct crypto_shash *hmac_tfm, +const u8 *label,unsigned int labellen, +const u8 *context,unsigned int contextlen, +u8 *okm,unsigned int okmlen);#endif
Signature · 1 line
2.43.0
Re: [PATCH 1/2] crypto: hkdf: add hkdf_expand_label()
Quoted 71 lines · On Wed, Aug 20, 2025 at 11:12:10AM +0200, [email protected] wrote:
From: Chris Leech <[email protected]>
Provide an implementation of RFC 8446 (TLS 1.3) HKDF-Expand-Label
Cc Eric Biggers <[email protected]>Signed-off-by Chris Leech <[email protected]>Signed-off-by Hannes Reinecke <[email protected]>--- crypto/hkdf.c | 55 +++++++++++++++++++++++++++++++++++++++++++ include/crypto/hkdf.h | 4 ++++ 2 files changed, 59 insertions(+)crypto/hkdf.c +44
-0@@ -11,6 +11,7 @@#include <crypto/sha2.h> #include <crypto/hkdf.h> #include <linux/module.h> +#include <linux/unaligned.h> /* * HKDF consists of two steps: @@ -129,6 +130,60 @@ int hkdf_expand(struct crypto_shash *hmac_tfm, }EXPORT_SYMBOL_GPL (hkdf_expand); +/** +* hkdf_expand_label - HKDF-Expand-Label (RFC 8846 section 7.1) +* @hmac_tfm: hash context keyed with pseudorandom key +* @label: ASCII label without "tls13 " prefix +* @label_len: length of @label +* @context: context bytes +* @contextlen: length of @context +* @okm: output keying material +* @okmlen: length of @okm +* +* Build the TLS 1.3 HkdfLabel structure and invoke hkdf_expand(). +* +* Returns 0 on success with output keying material stored in @okm, +* or a negative errno value otherwise. +*/ +int hkdf_expand_label (struct crypto_shash *hmac_tfm, +const u8 *label,unsigned int labellen, +const u8 *context,unsigned int contextlen, +u8 *okm,unsigned int okmlen) +{ +int err; +u8 *info; +unsigned int infolen; +static const char tls13_prefix[] ="tls13 " ; +unsigned int prefixlen =sizeof (tls13_prefix) -1 ;/* exclude NUL */ + +if (WARN_ON (labellen > (255 - prefixlen))) +return -EINVAL ; +if (WARN_ON (contextlen >255 )) +return -EINVAL ; + + infolen =2 + (1 + prefixlen + labellen) + (1 + contextlen); + info =kzalloc (infolen,GFP_KERNEL ); +if (!info) +return -ENOMEM ; + +/* HkdfLabel.Length */ +put_unaligned_be16 (okmlen, info); + +/* HkdfLabel.Label */ + info[2 ] = prefixlen + labellen; +memcpy (info +3 , tls13_prefix, prefixlen); +memcpy (info +3 + prefixlen, label, labellen);
crypto/hkdf.c int hkdf_expand(struct crypto_shash *hmac_tfm, · line 185
Quoted 10 lines
crypto/hkdf.c +10
-0+ +/* HkdfLabel.Context */ + info[3 + prefixlen + labellen] = contextlen; +memcpy (info +4 + prefixlen + labellen, context, contextlen); + + err =hkdf_expand (hmac_tfm, info, infolen, okm, okmlen); +kfree_sensitive (info); +return err; +} +EXPORT_SYMBOL_GPL (hkdf_expand_label);
Does this belong in crypto/hkdf.c? It seems to be specific to a particular user of HKDF.
- Eric
Re: [PATCH 1/2] crypto: hkdf: add hkdf_expand_label()
Quoted 13 lines · Eric Biggers
Quoted 12 lines · On Wed, Aug 20, 2025 at 11:12:10AM +0200, [email protected] wrote:
From: Chris Leech <[email protected]>
Provide an implementation of RFC 8446 (TLS 1.3) HKDF-Expand-Label
Cc Eric Biggers <[email protected]>Signed-off-by Chris Leech <[email protected]>Signed-off-by Hannes Reinecke <[email protected]>--- crypto/hkdf.c | 55 +++++++++++++++++++++++++++++++++++++++++++ include/crypto/hkdf.h | 4 ++++ 2 files changed, 59 insertions(+)
Quoted 4 lines
Quoted 1 line
...
Does this belong in
crypto/hkdf.c? It seems to be specific to a particular user of HKDF.
While this is needed for NVMe/TLS, it's a case of the NVMe specifications referencing a function defined in the TLS 1.3 RFC to be used. I though it would be clearest to fix the open-coded implemenation by creating an RFC complient function, which is now no-longer specific to NVMe so I moved it out to crypto/hkdf.c
I don't know that there will be other users, it just seemed to make the most sense there.
- Chris
Re: [PATCH 1/2] crypto: hkdf: add hkdf_expand_label()
Quoted 19 lines · Chris Leech
Quoted 13 lines · Eric Biggers
Quoted 12 lines · On Wed, Aug 20, 2025 at 11:12:10AM +0200, [email protected] wrote:
From: Chris Leech <[email protected]>
Provide an implementation of RFC 8446 (TLS 1.3) HKDF-Expand-Label
Cc Eric Biggers <[email protected]>Signed-off-by Chris Leech <[email protected]>Signed-off-by Hannes Reinecke <[email protected]>--- crypto/hkdf.c | 55 +++++++++++++++++++++++++++++++++++++++++++ include/crypto/hkdf.h | 4 ++++ 2 files changed, 59 insertions(+)Quoted 4 lines
Quoted 1 line
...
Does this belong in
crypto/hkdf.c? It seems to be specific to a particular user of HKDF.
Quoted 9 lines
While this is needed for NVMe/TLS, it's a case of the NVMe specifications referencing a function defined in the TLS 1.3 RFC to be used. I though it would be clearest to fix the open-coded implemenation by creating an RFC complient function, which is now no-longer specific to NVMe so I moved it out to
crypto/hkdf.cI don't know that there will be other users, it just seemed to make the most sense there.
But having said that, we can easily move it into the nvme code, and let others move it into crypto if there is a need.
Will be updating the patchset.
Cheers,
Hannes
Signature · 4 lines
Dr. Hannes Reinecke Kernel Storage Architect [email protected] +49 911 74053 688 SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich
kernel test robot
build botRe: [PATCH 1/2] crypto: hkdf: add hkdf_expand_label()
In reply to [email protected]kernel test robot noticed the following build warnings:
Hi,
kernel test robot noticed the following build warnings:
[auto build test WARNING on herbert-cryptodev-2.6/master]
[also build test WARNING on herbert-crypto-2.6/master linus/master v6.17-rc2 next-20250820] [cannot apply to hch-configfs/for-next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/hare-kernel-org/crypto-hkdf-add-hkdf_expand_label/20250820-172750 base: https://git.kernel.org/pub/scm/linux/kernel/git/herbert/cryptodev-2.6.git master patch link: https://lore.kernel.org/r/20250820091211.25368-2-hare%40kernel.org patch subject: [PATCH 1/2] crypto: hkdf: add hkdf_expand_label() config: loongarch-randconfig-001-20250821 (https://download.01.org/0day-ci/archive/20250821/[email protected]/config) compiler: loongarch64-linux-gcc (GCC) 14.3.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250821/[email protected]/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
All warnings (new ones prefixed by >>):
>> Warning: crypto/hkdf.c:151 function parameter 'labellen' not described in 'hkdf_expand_label'
Signature · 2 lines
0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki
PATCH 2/2 nvme-auth: use hkdf_expand_label()
In reply to [email protected]From: Hannes Reinecke <[email protected]>
When generating keying material during an authentication transaction (secure channel concatenation), the HKDF-Expand-Label function is part of the specified key derivation process.
The current open-coded implementation misses the length prefix requirements on the HkdfLabel label and context variable-length vectors (RFC 8446 Section 3.4).
Instead, use the hkdf_expand_label() function.
--- drivers/nvme/common/auth.c | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-)
drivers/nvme/common/auth.c +13 -20
@@ -715,10 +715,10 @@ int nvme_auth_derive_tls_psk(int hmac_id, u8 *psk, size_t psk_len, {struct crypto_shash *hmac_tfm;const char *hmac_name; -const char *psk_prefix ="tls13 nvme-tls-psk" ; +const char *label ="nvme-tls-psk" ;static const char default_salt[HKDF_MAX_HASHLEN ]; -size_t info_len, prk_len; -char *info; +size_t prk_len; +const char *ctx;unsigned char *prk, *tls_key;int ret;
@@ -758,36 +758,29 @@ int nvme_auth_derive_tls_psk(int hmac_id, u8 *psk, size_t psk_len,if (ret) goto out_free_prk; -/* -* 2 additional bytes for the length field from HDKF-Expand-Label, -* 2 additional bytes for the HMAC ID, and one byte for the space -* separator. -*/ - info_len =strlen (psk_digest) +strlen (psk_prefix) +5 ; - info =kzalloc (info_len +1 ,GFP_KERNEL ); -if (!info) { + ctx =kasprintf (GFP_KERNEL ,"%02d %s" , hmac_id, psk_digest); +if (!ctx) { ret = -ENOMEM ; goto out_free_prk; } -put_unaligned_be16 (psk_len, info); -memcpy (info +2 , psk_prefix,strlen (psk_prefix)); -sprintf (info +2 +strlen (psk_prefix),"%02d %s" , hmac_id, psk_digest); - tls_key =kzalloc (psk_len,GFP_KERNEL );if (!tls_key) { ret = -ENOMEM ; - goto out_free_info; + goto out_free_ctx; } - ret =hkdf_expand (hmac_tfm, info, info_len, tls_key, psk_len); + ret =hkdf_expand_label (hmac_tfm, + label,strlen (label), + ctx,strlen (ctx), + tls_key, psk_len);if (ret) {kfree (tls_key); - goto out_free_info; + goto out_free_ctx; } *ret_psk = tls_key; -out_free_info: -kfree (info); +out_free_ctx: +kfree (ctx); out_free_prk:kfree (prk); out_free_shash:
Signature · 1 line
2.43.0