Skip to content

Commit f3949db

Browse files
committed
linux: TLS PSK derivation fixes
There are issues with the Retained and TLS PSK derivations due to the implementation not adhering to the RFC 8446 definition of the HKDF-Expand-Label function. 1) The 16-bit HkdfLabel.length value must be converted to network byte order. 2) The variable length HkdfLabel.label and HkdfLabel.context vectors must be prefixed with a length byte. Reviewed-by: Hannes Reinecke <hare@suse.de> Link: https://lore.kernel.org/r/20250721021718.1159879-2-cleech@redhat.com Signed-off-by: Chris Leech <cleech@redhat.com>
1 parent b243904 commit f3949db

File tree

1 file changed

+57
-29
lines changed

1 file changed

+57
-29
lines changed

src/nvme/linux.c

Lines changed: 57 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -618,6 +618,46 @@ static DEFINE_CLEANUP_FUNC(
618618
cleanup_evp_pkey_ctx, EVP_PKEY_CTX *, EVP_PKEY_CTX_free)
619619
#define _cleanup_evp_pkey_ctx_ __cleanup__(cleanup_evp_pkey_ctx)
620620

621+
/*
622+
* hkdf_info_printf()
623+
*
624+
* Helper function to append variable length label and context to an HkdfLabel
625+
*
626+
* RFC 8446 (TLS 1.3) Section 7.1 defines the HKDF-Expand-Label function as a
627+
* specialization of the HKDF-Expand function (RFC 5869), where the info
628+
* parameter is structured as an HkdfLabel.
629+
*
630+
* An HkdfLabel structure includes two variable length vectors (label and
631+
* context) which must be preceded by their content length as per RFC 8446
632+
* Section 3.4 (and not NUL terminated as per Section 7.1). Additionally,
633+
* HkdfLabel.label must begin with "tls13 "
634+
*
635+
* Returns the number of bytes appended to the HKDF info buffer, or -1 on an
636+
* error.
637+
*/
638+
__attribute__((format(printf, 2, 3)))
639+
static int hkdf_info_printf(EVP_PKEY_CTX *ctx, char *fmt, ...)
640+
{
641+
_cleanup_free_ char *str = NULL;
642+
va_list myargs;
643+
uint8_t len;
644+
int ret;
645+
646+
va_start(myargs, fmt);
647+
ret = vasprintf(&str, fmt, myargs);
648+
va_end(myargs);
649+
if (ret < 0)
650+
return ret;
651+
if (ret > 255)
652+
return -1;
653+
len = ret;
654+
if (EVP_PKEY_CTX_add1_hkdf_info(ctx, (unsigned char *)&len, 1) <= 0)
655+
return -1;
656+
if (EVP_PKEY_CTX_add1_hkdf_info(ctx, (unsigned char *)str, len) <= 0)
657+
return -1;
658+
return (ret + 1);
659+
}
660+
621661
/*
622662
* derive_retained_key()
623663
*
@@ -652,7 +692,7 @@ static int derive_retained_key(int hmac, const char *hostnqn,
652692
size_t key_len)
653693
{
654694
_cleanup_evp_pkey_ctx_ EVP_PKEY_CTX *ctx = NULL;
655-
uint16_t length = key_len & 0xFFFF;
695+
uint16_t length = htons(key_len & 0xFFFF);
656696
const EVP_MD *md;
657697
size_t hmac_len;
658698

@@ -690,18 +730,11 @@ static int derive_retained_key(int hmac, const char *hostnqn,
690730
errno = ENOKEY;
691731
return -1;
692732
}
693-
if (EVP_PKEY_CTX_add1_hkdf_info(ctx,
694-
(const unsigned char *)"tls13 ", 6) <= 0) {
733+
if (hkdf_info_printf(ctx, "tls13 HostNQN") <= 0) {
695734
errno = ENOKEY;
696735
return -1;
697736
}
698-
if (EVP_PKEY_CTX_add1_hkdf_info(ctx,
699-
(const unsigned char *)"HostNQN", 7) <= 0) {
700-
errno = ENOKEY;
701-
return -1;
702-
}
703-
if (EVP_PKEY_CTX_add1_hkdf_info(ctx,
704-
(const unsigned char *)hostnqn, strlen(hostnqn)) <= 0) {
737+
if (hkdf_info_printf(ctx, "%s", hostnqn) <= 0) {
705738
errno = ENOKEY;
706739
return -1;
707740
}
@@ -736,12 +769,13 @@ static int derive_retained_key(int hmac, const char *hostnqn,
736769
*
737770
* and the value '0' is invalid here.
738771
*/
772+
739773
static int derive_tls_key(int version, unsigned char cipher,
740774
const char *context, unsigned char *retained,
741775
unsigned char *psk, size_t key_len)
742776
{
743777
_cleanup_evp_pkey_ctx_ EVP_PKEY_CTX *ctx = NULL;
744-
uint16_t length = key_len & 0xFFFF;
778+
uint16_t length = htons(key_len & 0xFFFF);
745779
const EVP_MD *md;
746780
size_t hmac_len;
747781

@@ -774,30 +808,24 @@ static int derive_tls_key(int version, unsigned char cipher,
774808
errno = ENOKEY;
775809
return -1;
776810
}
777-
if (EVP_PKEY_CTX_add1_hkdf_info(ctx,
778-
(const unsigned char *)"tls13 ", 6) <= 0) {
779-
errno = ENOKEY;
780-
return -1;
781-
}
782-
if (EVP_PKEY_CTX_add1_hkdf_info(ctx,
783-
(const unsigned char *)"nvme-tls-psk", 12) <= 0) {
811+
if (hkdf_info_printf(ctx, "tls13 nvme-tls-psk") <= 0) {
784812
errno = ENOKEY;
785813
return -1;
786814
}
787-
if (version == 1) {
788-
char hash_str[5];
789-
790-
sprintf(hash_str, "%02d ", cipher);
791-
if (EVP_PKEY_CTX_add1_hkdf_info(ctx,
792-
(const unsigned char *)hash_str,
793-
strlen(hash_str)) <= 0) {
815+
switch (version) {
816+
case 0:
817+
if (hkdf_info_printf(ctx, "%s", context) <= 0) {
794818
errno = ENOKEY;
795819
return -1;
796820
}
797-
}
798-
if (EVP_PKEY_CTX_add1_hkdf_info(ctx,
799-
(const unsigned char *)context,
800-
strlen(context)) <= 0) {
821+
break;
822+
case 1:
823+
if (hkdf_info_printf(ctx, "%02d %s", cipher, context) <= 0) {
824+
errno = ENOKEY;
825+
return -1;
826+
}
827+
break;
828+
default:
801829
errno = ENOKEY;
802830
return -1;
803831
}

0 commit comments

Comments
 (0)