Skip to content

Commit 25c9797

Browse files
committed
linux: fix HKDF TLS key derivation back to OpenSSL 3.0.8
OpenSSL prior to 3.3.1 had an issue with EVP_PKEY_CTX_add1_hkdf_info() where it acted like a 'set1' function instead of an 'add1' as documented. Work around that by building the entire info vector outside of the OpenSSL API and only calling this function once. This removes the hkdf_info_printf helper, which ended up being more of a hinderence with this change, in favor of building the info vector with calls like snprintf(p, 257, "%c%s", strlen(s), s) where HkdfLabel.label and HkdfLabel.context have a maxiumum length of 256 each. Signed-off-by: Chris Leech <[email protected]>
1 parent 32560ea commit 25c9797

1 file changed

Lines changed: 55 additions & 53 deletions

File tree

src/nvme/linux.c

Lines changed: 55 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -686,45 +686,8 @@ static DEFINE_CLEANUP_FUNC(
686686
cleanup_evp_pkey_ctx, EVP_PKEY_CTX *, EVP_PKEY_CTX_free)
687687
#define _cleanup_evp_pkey_ctx_ __cleanup__(cleanup_evp_pkey_ctx)
688688

689-
/*
690-
* hkdf_info_printf()
691-
*
692-
* Helper function to append variable length label and context to an HkdfLabel
693-
*
694-
* RFC 8446 (TLS 1.3) Section 7.1 defines the HKDF-Expand-Label function as a
695-
* specialization of the HKDF-Expand function (RFC 5869), where the info
696-
* parameter is structured as an HkdfLabel.
697-
*
698-
* An HkdfLabel structure includes two variable length vectors (label and
699-
* context) which must be preceded by their content length as per RFC 8446
700-
* Section 3.4 (and not NUL terminated as per Section 7.1). Additionally,
701-
* HkdfLabel.label must begin with "tls13 "
702-
*
703-
* Returns the number of bytes appended to the HKDF info buffer, or -1 on an
704-
* error.
705-
*/
706-
__attribute__((format(printf, 2, 3)))
707-
static int hkdf_info_printf(EVP_PKEY_CTX *ctx, char *fmt, ...)
708-
{
709-
_cleanup_free_ char *str;
710-
uint8_t len;
711-
int ret;
712-
va_list myargs;
713-
714-
va_start(myargs, fmt);
715-
ret = vasprintf(&str, fmt, myargs);
716-
va_end(myargs);
717-
if (ret < 0)
718-
return ret;
719-
if (ret > 255)
720-
return -1;
721-
len = ret;
722-
if (EVP_PKEY_CTX_add1_hkdf_info(ctx, (unsigned char *)&len, 1) <= 0)
723-
return -1;
724-
if (EVP_PKEY_CTX_add1_hkdf_info(ctx, (unsigned char *)str, len) <= 0)
725-
return -1;
726-
return (ret + 1);
727-
}
689+
/* NVMe is using the TLS 1.3 HkdfLabel structure */
690+
#define HKDF_INFO_MAX_LEN 514
728691

729692
/*
730693
* derive_retained_key()
@@ -760,9 +723,18 @@ static int derive_retained_key(int hmac, const char *hostnqn,
760723
size_t key_len)
761724
{
762725
_cleanup_evp_pkey_ctx_ EVP_PKEY_CTX *ctx = NULL;
763-
uint16_t length = htons(key_len & 0xFFFF);
726+
_cleanup_free_ uint8_t *hkdf_info = NULL;
764727
const EVP_MD *md;
765728
size_t hmac_len;
729+
char *pos;
730+
int ret;
731+
732+
/* +1 byte so that the snprintf terminating null can not overflow */
733+
hkdf_info = malloc(HKDF_INFO_MAX_LEN + 1);
734+
if (!hkdf_info) {
735+
errno = ENOMEM;
736+
return -1;
737+
}
766738

767739
if (hmac == NVME_HMAC_ALG_NONE) {
768740
memcpy(retained, configured, key_len);
@@ -793,16 +765,26 @@ static int derive_retained_key(int hmac, const char *hostnqn,
793765
errno = ENOKEY;
794766
return -1;
795767
}
796-
if (EVP_PKEY_CTX_add1_hkdf_info(ctx,
797-
(const unsigned char *)&length, 2) <= 0) {
768+
769+
pos = (char *)hkdf_info;
770+
*(uint16_t *)pos = htons(key_len & 0xFFFF);
771+
pos += sizeof(uint16_t);
772+
773+
ret = snprintf(pos, 257, "%ctls13 HostNQN", 13);
774+
if (ret <= 0 || ret > 256) {
798775
errno = ENOKEY;
799776
return -1;
800777
}
801-
if (hkdf_info_printf(ctx, "tls13 HostNQN") <= 0) {
778+
pos += ret;
779+
780+
ret = snprintf(pos, 257, "%c%s", (int) strlen(hostnqn), hostnqn);
781+
if (ret <= 0 || ret > 256) {
802782
errno = ENOKEY;
803783
return -1;
804784
}
805-
if (hkdf_info_printf(ctx, "%s", hostnqn) <= 0) {
785+
pos += ret;
786+
787+
if (EVP_PKEY_CTX_add1_hkdf_info(ctx, hkdf_info, (pos - (char *)hkdf_info)) <= 0) {
806788
errno = ENOKEY;
807789
return -1;
808790
}
@@ -911,9 +893,18 @@ static int derive_tls_key(int version, unsigned char cipher,
911893
unsigned char *psk, size_t key_len)
912894
{
913895
_cleanup_evp_pkey_ctx_ EVP_PKEY_CTX *ctx = NULL;
914-
uint16_t length = htons(key_len & 0xFFFF);
896+
_cleanup_free_ uint8_t *hkdf_info = NULL;
915897
const EVP_MD *md;
916898
size_t hmac_len;
899+
char *pos;
900+
int ret;
901+
902+
/* +1 byte so that the snprintf terminating null can not overflow */
903+
hkdf_info = malloc(HKDF_INFO_MAX_LEN + 1);
904+
if (!hkdf_info) {
905+
errno = ENOMEM;
906+
return -1;
907+
}
917908

918909
md = select_hmac(cipher, &hmac_len);
919910
if (!md || !hmac_len) {
@@ -939,33 +930,44 @@ static int derive_tls_key(int version, unsigned char cipher,
939930
errno = ENOKEY;
940931
return -1;
941932
}
942-
if (EVP_PKEY_CTX_add1_hkdf_info(ctx,
943-
(const unsigned char *)&length, 2) <= 0) {
944-
errno = ENOKEY;
945-
return -1;
946-
}
947-
if (hkdf_info_printf(ctx, "tls13 nvme-tls-psk") <= 0) {
933+
934+
pos = (char *)hkdf_info;
935+
*(uint16_t *)pos = htons(key_len & 0xFFFF);
936+
pos += sizeof(uint16_t);
937+
938+
ret = snprintf(pos, 257, "%ctls13 nvme-tls-psk", 18);
939+
if (ret <= 0 || ret > 256) {
948940
errno = ENOKEY;
949941
return -1;
950942
}
943+
pos += ret;
944+
951945
switch (version) {
952946
case 0:
953-
if (hkdf_info_printf(ctx, "%s", context) <= 0) {
947+
ret = snprintf(pos, 257, "%c%s", (int) strlen(context), context);
948+
if (ret <= 0 || ret > 256) {
954949
errno = ENOKEY;
955950
return -1;
956951
}
952+
pos += ret;
957953
break;
958954
case 1:
959-
if (hkdf_info_printf(ctx, "%02d %s", cipher, context) <= 0) {
955+
ret = snprintf(pos, 257, "%c%02d %s", (int) strlen(context) + 3, cipher, context);
956+
if (ret <= 0 || ret > 256) {
960957
errno = ENOKEY;
961958
return -1;
962959
}
960+
pos += ret;
963961
break;
964962
default:
965963
errno = ENOKEY;
966964
return -1;
967965
}
968966

967+
if (EVP_PKEY_CTX_add1_hkdf_info(ctx, hkdf_info, (pos - (char *)hkdf_info)) <= 0) {
968+
errno = ENOKEY;
969+
return -1;
970+
}
969971
if (EVP_PKEY_derive(ctx, psk, &key_len) <= 0) {
970972
errno = ENOKEY;
971973
return -1;

0 commit comments

Comments
 (0)