Skip to content

Commit e48845e

Browse files
hreineckeigaw
authored andcommitted
linux: fixup PSK HMAC type '0' handling
The NVMe TCP spec defines a PSK HMAC type '0', which indicates that the configured key should be used as a retained key with no transformation in between. Signed-off-by: Hannes Reinecke <[email protected]> Signed-off-by: Daniel Wagner <[email protected]>
1 parent dd1daf3 commit e48845e

1 file changed

Lines changed: 111 additions & 23 deletions

File tree

src/nvme/linux.c

Lines changed: 111 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,11 @@ char *nvme_get_path_attr(nvme_path_t p, const char *attr)
525525
}
526526

527527
#ifndef CONFIG_OPENSSL
528+
static unsigned char default_hmac(size_t key_len)
529+
{
530+
return NVME_HMAC_ALG_NONE;
531+
}
532+
528533
int nvme_gen_dhchap_key(char *hostnqn, enum nvme_hmac_alg hmac,
529534
unsigned int key_len, unsigned char *secret,
530535
unsigned char *key)
@@ -552,7 +557,7 @@ static int derive_retained_key(int hmac, const char *hostnqn,
552557
}
553558

554559
static int derive_psk_digest(const char *hostnqn, const char *subsysnqn,
555-
int version, int hmac,
560+
int version, int cipher,
556561
unsigned char *retained, size_t key_len,
557562
char *digest, size_t digest_len)
558563
{
@@ -562,7 +567,7 @@ static int derive_psk_digest(const char *hostnqn, const char *subsysnqn,
562567
return -1;
563568
}
564569

565-
static int derive_tls_key(int version, int hmac, const char *context,
570+
static int derive_tls_key(int version, int cipher, const char *context,
566571
unsigned char *retained,
567572
unsigned char *psk, size_t key_len)
568573
{
@@ -572,20 +577,41 @@ static int derive_tls_key(int version, int hmac, const char *context,
572577
return -1;
573578
}
574579
#else /* CONFIG_OPENSSL */
575-
static const EVP_MD *select_hmac(int hmac, size_t *key_len)
580+
static unsigned char default_hmac(size_t key_len)
581+
{
582+
unsigned char hmac = NVME_HMAC_ALG_NONE;
583+
584+
switch (key_len) {
585+
case 32:
586+
hmac = NVME_HMAC_ALG_SHA2_256;
587+
break;
588+
case 48:
589+
hmac = NVME_HMAC_ALG_SHA2_384;
590+
break;
591+
case 64:
592+
hmac = NVME_HMAC_ALG_SHA2_512;
593+
break;
594+
default:
595+
break;
596+
}
597+
return hmac;
598+
}
599+
600+
static const EVP_MD *select_hmac(int hmac, size_t *hmac_len)
576601
{
577602
const EVP_MD *md = NULL;
578603

579604
switch (hmac) {
580605
case NVME_HMAC_ALG_SHA2_256:
581606
md = EVP_sha256();
582-
*key_len = 32;
607+
*hmac_len = 32;
583608
break;
584609
case NVME_HMAC_ALG_SHA2_384:
585610
md = EVP_sha384();
586-
*key_len = 48;
611+
*hmac_len = 48;
587612
break;
588613
default:
614+
*hmac_len = 0;
589615
break;
590616
}
591617
return md;
@@ -595,8 +621,36 @@ static DEFINE_CLEANUP_FUNC(
595621
cleanup_evp_pkey_ctx, EVP_PKEY_CTX *, EVP_PKEY_CTX_free)
596622
#define _cleanup_evp_pkey_ctx_ __cleanup__(cleanup_evp_pkey_ctx)
597623

624+
/*
625+
* derive_retained_key()
626+
*
627+
* Derive a retained key according to NVMe TCP Transport specification:
628+
*
629+
* The retained PSK is derived from the configured PSK. The configured PSK
630+
* shall be destroyed as soon as the retained PSK is generated and stored.
631+
* Each NVMe/TCP entity shall support:
632+
* 1) transforming the configured PSK into a retained PSK before it is stored
633+
* by the NVMe/TCP entity for repeated use with another NVMe/TCP entity; and
634+
* 2) using the configured PSK as a retained PSK.
635+
*
636+
* The method to derive a retained PSK from a configured PSK shall be using
637+
* the HKDF-Extract and HKDF-Expand-Label operations (refer to RFC 5869 and
638+
* RFC 8446):
639+
* 1. PRK = HKDF-Extract(0, Configured PSK); and
640+
* 2. Retained PSK = HKDF-Expand-Label(PRK, “HostNQN”, NQNh,
641+
* Length(Configured PSK)),
642+
* where NQNh is the NQN of the host.
643+
*
644+
* 'hmac' indicates the hash function to be used to transform the configured
645+
* PSK in a retained PSK, encoded as follows:
646+
*
647+
* - 0 indicates no transform (i.e., the configured PSK is used as a
648+
* retained PSK)
649+
* - 1 indicates SHA-256
650+
* - 2 indicates SHA-384
651+
*/
598652
static int derive_retained_key(int hmac, const char *hostnqn,
599-
unsigned char *generated,
653+
unsigned char *configured,
600654
unsigned char *retained,
601655
size_t key_len)
602656
{
@@ -605,8 +659,13 @@ static int derive_retained_key(int hmac, const char *hostnqn,
605659
const EVP_MD *md;
606660
size_t hmac_len;
607661

662+
if (hmac == NVME_HMAC_ALG_NONE) {
663+
memcpy(retained, configured, key_len);
664+
return key_len;
665+
}
666+
608667
md = select_hmac(hmac, &hmac_len);
609-
if (!md || hmac_len > key_len) {
668+
if (!md || !hmac_len) {
610669
errno = EINVAL;
611670
return -1;
612671
}
@@ -625,7 +684,7 @@ static int derive_retained_key(int hmac, const char *hostnqn,
625684
errno = ENOKEY;
626685
return -1;
627686
}
628-
if (EVP_PKEY_CTX_set1_hkdf_key(ctx, generated, key_len) <= 0) {
687+
if (EVP_PKEY_CTX_set1_hkdf_key(ctx, configured, key_len) <= 0) {
629688
errno = ENOKEY;
630689
return -1;
631690
}
@@ -658,17 +717,39 @@ static int derive_retained_key(int hmac, const char *hostnqn,
658717
return key_len;
659718
}
660719

661-
static int derive_tls_key(int version, int hmac, const char *context,
662-
unsigned char *retained,
720+
/*
721+
* derive_tls_key()
722+
*
723+
* Derive a TLS PSK from a retained PSK.
724+
*
725+
* The TLS PSK shall be derived as follows from an input PSK (i.e., either
726+
* a retained PSK or a generated PSK) and a PSK identity using the HKDF-Extract
727+
* and HKDF-Expand-Label operations (refer to RFC 5869 and RFC 8446) where the
728+
* hash function is the one specified by the hash specifier of the PSK identity:
729+
* 1. PRK = HKDF-Extract(0, Input PSK); and
730+
* 2. TLS PSK = HKDF-Expand-Label(PRK, “nvme-tls-psk”, PskIdentity, L),
731+
* where PskIdentity is the PSK identity and L is the output size in bytes of
732+
* the hash function (i.e., 32 for SHA-256 and 48 for SHA-384).
733+
*
734+
* Note that this is _not_ the hash value as specified by the configured key,
735+
* but rather the hash function of the cipher suite associated with the
736+
* PSK:
737+
* - 1 indicates SHA-245 (for the TLS_AES_128_GCM_SHA256 cipher suite)
738+
* - 2 indicates SHA-384 (for the TLS_AES_256_GCM_SHA384 cipher suite)
739+
*
740+
* and the value '0' is invalid here.
741+
*/
742+
static int derive_tls_key(int version, unsigned char cipher,
743+
const char *context, unsigned char *retained,
663744
unsigned char *psk, size_t key_len)
664745
{
665746
_cleanup_evp_pkey_ctx_ EVP_PKEY_CTX *ctx = NULL;
666747
uint16_t length = key_len & 0xFFFF;
667748
const EVP_MD *md;
668749
size_t hmac_len;
669750

670-
md = select_hmac(hmac, &hmac_len);
671-
if (!md || hmac_len > key_len) {
751+
md = select_hmac(cipher, &hmac_len);
752+
if (!md || !hmac_len) {
672753
errno = EINVAL;
673754
return -1;
674755
}
@@ -707,9 +788,9 @@ static int derive_tls_key(int version, int hmac, const char *context,
707788
return -1;
708789
}
709790
if (version == 1) {
710-
char hash_str[4];
791+
char hash_str[5];
711792

712-
sprintf(hash_str, "%02d ", hmac);
793+
sprintf(hash_str, "%02d ", cipher);
713794
if (EVP_PKEY_CTX_add1_hkdf_info(ctx,
714795
(const unsigned char *)hash_str,
715796
strlen(hash_str)) <= 0) {
@@ -816,7 +897,8 @@ static int derive_psk_digest(const char *hostnqn, const char *subsysnqn,
816897
errno = ENOMEM;
817898
return -1;
818899
}
819-
if (!md) {
900+
md = select_hmac(cipher, &hmac_len);
901+
if (!md || !hmac_len) {
820902
errno = EINVAL;
821903
return -1;
822904
}
@@ -965,7 +1047,7 @@ int nvme_gen_dhchap_key(char *hostnqn, enum nvme_hmac_alg hmac,
9651047
}
9661048

9671049
static int derive_psk_digest(const char *hostnqn, const char *subsysnqn,
968-
int version, int hmac,
1050+
int version, int cipher,
9691051
unsigned char *retained, size_t key_len,
9701052
char *digest, size_t digest_len)
9711053
{
@@ -996,7 +1078,7 @@ static int derive_psk_digest(const char *hostnqn, const char *subsysnqn,
9961078
errno = ENOMEM;
9971079
return -1;
9981080
}
999-
switch (hmac) {
1081+
switch (cipher) {
10001082
case NVME_HMAC_ALG_SHA2_256:
10011083
dig = OSSL_DIGEST_NAME_SHA2_256;
10021084
break;
@@ -1069,12 +1151,12 @@ static int derive_psk_digest(const char *hostnqn, const char *subsysnqn,
10691151
#endif /* !CONFIG_OPENSSL_3 */
10701152

10711153
static int gen_tls_identity(const char *hostnqn, const char *subsysnqn,
1072-
int version, int hmac, char *digest,
1154+
int version, int cipher, char *digest,
10731155
char *identity)
10741156
{
10751157
if (version == 0) {
10761158
sprintf(identity, "NVMe%01dR%02d %s %s",
1077-
version, hmac, hostnqn, subsysnqn);
1159+
version, cipher, hostnqn, subsysnqn);
10781160
return strlen(identity);
10791161
}
10801162
if (version > 1) {
@@ -1083,7 +1165,7 @@ static int gen_tls_identity(const char *hostnqn, const char *subsysnqn,
10831165
}
10841166

10851167
sprintf(identity, "NVMe%01dR%02d %s %s %s",
1086-
version, hmac, hostnqn, subsysnqn, digest);
1168+
version, cipher, hostnqn, subsysnqn, digest);
10871169
return strlen(identity);
10881170
}
10891171

@@ -1095,6 +1177,7 @@ static int derive_nvme_keys(const char *hostnqn, const char *subsysnqn,
10951177
_cleanup_free_ unsigned char *retained = NULL;
10961178
_cleanup_free_ char *digest = NULL;
10971179
char *context = identity;
1180+
unsigned char cipher;
10981181
int ret = -1;
10991182

11001183
if (!hostnqn || !subsysnqn || !identity || !psk) {
@@ -1111,6 +1194,11 @@ static int derive_nvme_keys(const char *hostnqn, const char *subsysnqn,
11111194
if (ret < 0)
11121195
return ret;
11131196

1197+
if (hmac == NVME_HMAC_ALG_NONE)
1198+
cipher = default_hmac(key_len);
1199+
else
1200+
cipher = hmac;
1201+
11141202
if (version == 1) {
11151203
size_t digest_len = 2 * key_len;
11161204

@@ -1119,18 +1207,18 @@ static int derive_nvme_keys(const char *hostnqn, const char *subsysnqn,
11191207
errno = ENOMEM;
11201208
return -1;
11211209
}
1122-
ret = derive_psk_digest(hostnqn, subsysnqn, version, hmac,
1210+
ret = derive_psk_digest(hostnqn, subsysnqn, version, cipher,
11231211
retained, key_len,
11241212
digest, digest_len);
11251213
if (ret < 0)
11261214
return ret;
11271215
context = digest;
11281216
}
1129-
ret = gen_tls_identity(hostnqn, subsysnqn, version, hmac,
1217+
ret = gen_tls_identity(hostnqn, subsysnqn, version, cipher,
11301218
digest, identity);
11311219
if (ret < 0)
11321220
return ret;
1133-
return derive_tls_key(version, hmac, context, retained,
1221+
return derive_tls_key(version, cipher, context, retained,
11341222
psk, key_len);
11351223
}
11361224

0 commit comments

Comments
 (0)