@@ -600,6 +600,17 @@ static int derive_retained_key(int hmac, const char *hostnqn,
600600 return -1 ;
601601}
602602
603+ static int derive_retained_key_compat (int hmac , const char * hostnqn ,
604+ unsigned char * generated ,
605+ unsigned char * retained ,
606+ size_t key_len )
607+ {
608+ nvme_msg (NULL , LOG_ERR , "NVMe TLS is not supported; "
609+ "recompile with OpenSSL support.\n" );
610+ errno = ENOTSUP ;
611+ return -1 ;
612+ }
613+
603614static int derive_psk_digest (const char * hostnqn , const char * subsysnqn ,
604615 int version , int cipher ,
605616 unsigned char * retained , size_t key_len ,
@@ -620,6 +631,16 @@ static int derive_tls_key(int version, int cipher, const char *context,
620631 errno = ENOTSUP ;
621632 return -1 ;
622633}
634+
635+ static int derive_tls_key_compat (int version , int cipher , const char * context ,
636+ unsigned char * retained ,
637+ unsigned char * psk , size_t key_len )
638+ {
639+ nvme_msg (NULL , LOG_ERR , "NVMe TLS is not supported; "
640+ "recompile with OpenSSL support.\n" );
641+ errno = ENOTSUP ;
642+ return -1 ;
643+ }
623644#else /* CONFIG_OPENSSL */
624645static unsigned char default_hmac (size_t key_len )
625646{
@@ -665,6 +686,46 @@ static DEFINE_CLEANUP_FUNC(
665686 cleanup_evp_pkey_ctx , EVP_PKEY_CTX * , EVP_PKEY_CTX_free )
666687#define _cleanup_evp_pkey_ctx_ __cleanup__(cleanup_evp_pkey_ctx)
667688
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+ }
728+
668729/*
669730 * derive_retained_key()
670731 *
@@ -697,6 +758,67 @@ static int derive_retained_key(int hmac, const char *hostnqn,
697758 unsigned char * configured ,
698759 unsigned char * retained ,
699760 size_t key_len )
761+ {
762+ _cleanup_evp_pkey_ctx_ EVP_PKEY_CTX * ctx = NULL ;
763+ uint16_t length = htons (key_len & 0xFFFF );
764+ const EVP_MD * md ;
765+ size_t hmac_len ;
766+
767+ if (hmac == NVME_HMAC_ALG_NONE ) {
768+ memcpy (retained , configured , key_len );
769+ return key_len ;
770+ }
771+
772+ md = select_hmac (hmac , & hmac_len );
773+ if (!md || !hmac_len ) {
774+ errno = EINVAL ;
775+ return -1 ;
776+ }
777+
778+ ctx = EVP_PKEY_CTX_new_id (EVP_PKEY_HKDF , NULL );
779+ if (!ctx ) {
780+ errno = ENOMEM ;
781+ return -1 ;
782+ }
783+
784+ if (EVP_PKEY_derive_init (ctx ) <= 0 ) {
785+ errno = ENOMEM ;
786+ return -1 ;
787+ }
788+ if (EVP_PKEY_CTX_set_hkdf_md (ctx , md ) <= 0 ) {
789+ errno = ENOKEY ;
790+ return -1 ;
791+ }
792+ if (EVP_PKEY_CTX_set1_hkdf_key (ctx , configured , key_len ) <= 0 ) {
793+ errno = ENOKEY ;
794+ return -1 ;
795+ }
796+ if (EVP_PKEY_CTX_add1_hkdf_info (ctx ,
797+ (const unsigned char * )& length , 2 ) <= 0 ) {
798+ errno = ENOKEY ;
799+ return -1 ;
800+ }
801+ if (hkdf_info_printf (ctx , "tls13 HostNQN" ) <= 0 ) {
802+ errno = ENOKEY ;
803+ return -1 ;
804+ }
805+ if (hkdf_info_printf (ctx , "%s" , hostnqn ) <= 0 ) {
806+ errno = ENOKEY ;
807+ return -1 ;
808+ }
809+
810+ if (EVP_PKEY_derive (ctx , retained , & key_len ) <= 0 ) {
811+ errno = ENOKEY ;
812+ return -1 ;
813+ }
814+
815+ return key_len ;
816+ }
817+
818+ static int derive_retained_key_compat (int hmac , const char * hostnqn ,
819+ unsigned char * configured ,
820+ unsigned char * retained ,
821+ size_t key_len )
700822{
701823 _cleanup_evp_pkey_ctx_ EVP_PKEY_CTX * ctx = NULL ;
702824 uint16_t length = key_len & 0xFFFF ;
@@ -783,9 +905,78 @@ static int derive_retained_key(int hmac, const char *hostnqn,
783905 *
784906 * and the value '0' is invalid here.
785907 */
908+
786909static int derive_tls_key (int version , unsigned char cipher ,
787910 const char * context , unsigned char * retained ,
788911 unsigned char * psk , size_t key_len )
912+ {
913+ _cleanup_evp_pkey_ctx_ EVP_PKEY_CTX * ctx = NULL ;
914+ uint16_t length = htons (key_len & 0xFFFF );
915+ const EVP_MD * md ;
916+ size_t hmac_len ;
917+
918+ md = select_hmac (cipher , & hmac_len );
919+ if (!md || !hmac_len ) {
920+ errno = EINVAL ;
921+ return -1 ;
922+ }
923+
924+ ctx = EVP_PKEY_CTX_new_id (EVP_PKEY_HKDF , NULL );
925+ if (!ctx ) {
926+ errno = ENOMEM ;
927+ return -1 ;
928+ }
929+
930+ if (EVP_PKEY_derive_init (ctx ) <= 0 ) {
931+ errno = ENOMEM ;
932+ return -1 ;
933+ }
934+ if (EVP_PKEY_CTX_set_hkdf_md (ctx , md ) <= 0 ) {
935+ errno = ENOKEY ;
936+ return -1 ;
937+ }
938+ if (EVP_PKEY_CTX_set1_hkdf_key (ctx , retained , key_len ) <= 0 ) {
939+ errno = ENOKEY ;
940+ return -1 ;
941+ }
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 ) {
948+ errno = ENOKEY ;
949+ return -1 ;
950+ }
951+ switch (version ) {
952+ case 0 :
953+ if (hkdf_info_printf (ctx , "%s" , context ) <= 0 ) {
954+ errno = ENOKEY ;
955+ return -1 ;
956+ }
957+ break ;
958+ case 1 :
959+ if (hkdf_info_printf (ctx , "%02d %s" , cipher , context ) <= 0 ) {
960+ errno = ENOKEY ;
961+ return -1 ;
962+ }
963+ break ;
964+ default :
965+ errno = ENOKEY ;
966+ return -1 ;
967+ }
968+
969+ if (EVP_PKEY_derive (ctx , psk , & key_len ) <= 0 ) {
970+ errno = ENOKEY ;
971+ return -1 ;
972+ }
973+
974+ return key_len ;
975+ }
976+
977+ static int derive_tls_key_compat (int version , unsigned char cipher ,
978+ const char * context , unsigned char * retained ,
979+ unsigned char * psk , size_t key_len )
789980{
790981 _cleanup_evp_pkey_ctx_ EVP_PKEY_CTX * ctx = NULL ;
791982 uint16_t length = key_len & 0xFFFF ;
@@ -1074,7 +1265,7 @@ static int gen_tls_identity(const char *hostnqn, const char *subsysnqn,
10741265static int derive_nvme_keys (const char * hostnqn , const char * subsysnqn ,
10751266 char * identity , int version ,
10761267 int hmac , unsigned char * configured ,
1077- unsigned char * psk , int key_len )
1268+ unsigned char * psk , int key_len , bool compat )
10781269{
10791270 _cleanup_free_ unsigned char * retained = NULL ;
10801271 _cleanup_free_ char * digest = NULL ;
@@ -1092,7 +1283,12 @@ static int derive_nvme_keys(const char *hostnqn, const char *subsysnqn,
10921283 errno = ENOMEM ;
10931284 return -1 ;
10941285 }
1095- ret = derive_retained_key (hmac , hostnqn , configured , retained , key_len );
1286+ if (compat )
1287+ ret = derive_retained_key_compat (hmac , hostnqn , configured ,
1288+ retained , key_len );
1289+ else
1290+ ret = derive_retained_key (hmac , hostnqn , configured ,
1291+ retained , key_len );
10961292 if (ret < 0 )
10971293 return ret ;
10981294
@@ -1120,6 +1316,9 @@ static int derive_nvme_keys(const char *hostnqn, const char *subsysnqn,
11201316 digest , identity );
11211317 if (ret < 0 )
11221318 return ret ;
1319+ if (compat )
1320+ return derive_tls_key_compat (version , cipher , context , retained ,
1321+ psk , key_len );
11231322 return derive_tls_key (version , cipher , context , retained ,
11241323 psk , key_len );
11251324}
@@ -1175,10 +1374,47 @@ char *nvme_generate_tls_key_identity(const char *hostnqn, const char *subsysnqn,
11751374
11761375 memset (psk , 0 , key_len );
11771376 ret = derive_nvme_keys (hostnqn , subsysnqn , identity , version , hmac ,
1178- configured_key , psk , key_len );
1377+ configured_key , psk , key_len , false);
1378+ out_free_identity :
1379+ if (ret < 0 ) {
1380+ free (identity );
1381+ identity = NULL ;
1382+ }
1383+ return identity ;
1384+ }
1385+
1386+ char * nvme_generate_tls_key_identity_compat (const char * hostnqn , const char * subsysnqn ,
1387+ int version , int hmac ,
1388+ unsigned char * configured_key , int key_len )
1389+ {
1390+ _cleanup_free_ unsigned char * psk = NULL ;
1391+ char * identity ;
1392+ ssize_t identity_len ;
1393+ int ret = -1 ;
1394+
1395+ identity_len = nvme_identity_len (hmac , version , hostnqn , subsysnqn );
1396+ if (identity_len < 0 ) {
1397+ errno = EINVAL ;
1398+ return NULL ;
1399+ }
1400+
1401+ identity = malloc (identity_len );
1402+ if (!identity ) {
1403+ errno = ENOMEM ;
1404+ return NULL ;
1405+ }
1406+
1407+ psk = malloc (key_len );
1408+ if (!psk ) {
1409+ errno = ENOMEM ;
1410+ goto out_free_identity ;
1411+ }
1412+
1413+ memset (psk , 0 , key_len );
1414+ ret = derive_nvme_keys (hostnqn , subsysnqn , identity , version , hmac ,
1415+ configured_key , psk , key_len , true);
11791416out_free_identity :
11801417 if (ret < 0 ) {
1181- errno = - ret ;
11821418 free (identity );
11831419 identity = NULL ;
11841420 }
@@ -1347,7 +1583,8 @@ int nvme_scan_tls_keys(const char *keyring, nvme_scan_tls_keys_cb_t cb,
13471583static long __nvme_insert_tls_key (key_serial_t keyring_id , const char * key_type ,
13481584 const char * hostnqn , const char * subsysnqn ,
13491585 int version , int hmac ,
1350- unsigned char * configured_key , int key_len )
1586+ unsigned char * configured_key , int key_len ,
1587+ bool compat )
13511588{
13521589 _cleanup_free_ unsigned char * psk = NULL ;
13531590 _cleanup_free_ char * identity = NULL ;
@@ -1373,7 +1610,7 @@ static long __nvme_insert_tls_key(key_serial_t keyring_id, const char *key_type,
13731610 }
13741611 memset (psk , 0 , key_len );
13751612 ret = derive_nvme_keys (hostnqn , subsysnqn , identity , version , hmac ,
1376- configured_key , psk , key_len );
1613+ configured_key , psk , key_len , compat );
13771614 if (ret != key_len ) {
13781615 errno = ENOKEY ;
13791616 return 0 ;
@@ -1404,7 +1641,30 @@ long nvme_insert_tls_key_versioned(const char *keyring, const char *key_type,
14041641 return __nvme_insert_tls_key (keyring_id , key_type ,
14051642 hostnqn , subsysnqn ,
14061643 version , hmac ,
1407- configured_key , key_len );
1644+ configured_key , key_len , false);
1645+ }
1646+
1647+ long nvme_insert_tls_key_compat (const char * keyring , const char * key_type ,
1648+ const char * hostnqn , const char * subsysnqn ,
1649+ int version , int hmac ,
1650+ unsigned char * configured_key , int key_len )
1651+ {
1652+ key_serial_t keyring_id ;
1653+ int ret ;
1654+
1655+ keyring_id = nvme_lookup_keyring (keyring );
1656+ if (keyring_id == 0 ) {
1657+ errno = ENOKEY ;
1658+ return 0 ;
1659+ }
1660+
1661+ ret = nvme_set_keyring (keyring_id );
1662+ if (ret < 0 )
1663+ return 0 ;
1664+ return __nvme_insert_tls_key (keyring_id , key_type ,
1665+ hostnqn , subsysnqn ,
1666+ version , hmac ,
1667+ configured_key , key_len , true);
14081668}
14091669
14101670long nvme_revoke_tls_key (const char * keyring , const char * key_type ,
@@ -1450,7 +1710,7 @@ static long __nvme_import_tls_key(long keyring_id,
14501710 return __nvme_insert_tls_key (keyring_id , "psk" ,
14511711 hostnqn , subsysnqn ,
14521712 version , hmac ,
1453- key_data , key_len );
1713+ key_data , key_len , false );
14541714 }
14551715
14561716 return nvme_update_key (keyring_id , "psk" , identity ,
0 commit comments