@@ -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+
528533int 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
554559static 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+ */
598652static 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
9671049static 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
10711153static 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