Skip to content

Commit a7ae73c

Browse files
committed
Add nvme_import_tls_key_compat()
Add a compability version nvme_import_tls_key_compat() to allow for compability with older implementations which were implementing HKDF-Expand-Label without prefixing the 'info' and 'label' strings with the length. Signed-off-by: Hannes Reinecke <[email protected]>
1 parent c79d956 commit a7ae73c

3 files changed

Lines changed: 219 additions & 18 deletions

File tree

src/libnvme.map

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ LIBNVME_UNRELEASED {
33
global:
44
nvme_set_etdas;
55
nvme_clear_etdas;
6+
nvme_import_tls_key_compat;
67
};
78

89
LIBNVME_1_14 {

src/nvme/linux.c

Lines changed: 192 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,74 @@ static int derive_retained_key(int hmac, const char *hostnqn,
794794
return key_len;
795795
}
796796

797+
static int derive_retained_key_compat(int hmac, const char *hostnqn,
798+
unsigned char *configured,
799+
unsigned char *retained,
800+
size_t key_len)
801+
{
802+
_cleanup_evp_pkey_ctx_ EVP_PKEY_CTX *ctx = NULL;
803+
uint16_t length = htons(key_len & 0xFFFF);
804+
const EVP_MD *md;
805+
size_t hmac_len;
806+
807+
if (hmac == NVME_HMAC_ALG_NONE) {
808+
memcpy(retained, configured, key_len);
809+
return key_len;
810+
}
811+
812+
md = select_hmac(hmac, &hmac_len);
813+
if (!md || !hmac_len) {
814+
errno = EINVAL;
815+
return -1;
816+
}
817+
818+
ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
819+
if (!ctx) {
820+
errno = ENOMEM;
821+
return -1;
822+
}
823+
824+
if (EVP_PKEY_derive_init(ctx) <= 0) {
825+
errno = ENOMEM;
826+
return -1;
827+
}
828+
if (EVP_PKEY_CTX_set_hkdf_md(ctx, md) <= 0) {
829+
errno = ENOKEY;
830+
return -1;
831+
}
832+
if (EVP_PKEY_CTX_set1_hkdf_key(ctx, configured, key_len) <= 0) {
833+
errno = ENOKEY;
834+
return -1;
835+
}
836+
if (EVP_PKEY_CTX_add1_hkdf_info(ctx,
837+
(const unsigned char *)&length, 2) <= 0) {
838+
errno = ENOKEY;
839+
return -1;
840+
}
841+
if (EVP_PKEY_CTX_add1_hkdf_info(ctx,
842+
(const unsigned char *)"tls13 ", 6) <= 0) {
843+
errno = ENOKEY;
844+
return -1;
845+
}
846+
if (EVP_PKEY_CTX_add1_hkdf_info(ctx,
847+
(const unsigned char *)"HostNQN", 7) <= 0) {
848+
errno = ENOKEY;
849+
return -1;
850+
}
851+
if (EVP_PKEY_CTX_add1_hkdf_info(ctx,
852+
(const unsigned char *)hostnqn, strlen(hostnqn)) <= 0) {
853+
errno = ENOKEY;
854+
return -1;
855+
}
856+
857+
if (EVP_PKEY_derive(ctx, retained, &key_len) <= 0) {
858+
errno = ENOKEY;
859+
return -1;
860+
}
861+
862+
return key_len;
863+
}
864+
797865
/*
798866
* derive_tls_key()
799867
*
@@ -885,6 +953,80 @@ static int derive_tls_key(int version, unsigned char cipher,
885953
return key_len;
886954
}
887955

956+
static int derive_tls_key_compat(int version, unsigned char cipher,
957+
const char *context, unsigned char *retained,
958+
unsigned char *psk, size_t key_len)
959+
{
960+
_cleanup_evp_pkey_ctx_ EVP_PKEY_CTX *ctx = NULL;
961+
uint16_t length = htons(key_len & 0xFFFF);
962+
const EVP_MD *md;
963+
size_t hmac_len;
964+
965+
md = select_hmac(cipher, &hmac_len);
966+
if (!md || !hmac_len) {
967+
errno = EINVAL;
968+
return -1;
969+
}
970+
971+
ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
972+
if (!ctx) {
973+
errno = ENOMEM;
974+
return -1;
975+
}
976+
977+
if (EVP_PKEY_derive_init(ctx) <= 0) {
978+
errno = ENOMEM;
979+
return -1;
980+
}
981+
if (EVP_PKEY_CTX_set_hkdf_md(ctx, md) <= 0) {
982+
errno = ENOKEY;
983+
return -1;
984+
}
985+
if (EVP_PKEY_CTX_set1_hkdf_key(ctx, retained, key_len) <= 0) {
986+
errno = ENOKEY;
987+
return -1;
988+
}
989+
if (EVP_PKEY_CTX_add1_hkdf_info(ctx,
990+
(const unsigned char *)&length, 2) <= 0) {
991+
errno = ENOKEY;
992+
return -1;
993+
}
994+
if (EVP_PKEY_CTX_add1_hkdf_info(ctx,
995+
(const unsigned char *)"tls13 ", 6) <= 0) {
996+
errno = ENOKEY;
997+
return -1;
998+
}
999+
if (EVP_PKEY_CTX_add1_hkdf_info(ctx,
1000+
(const unsigned char *)"nvme-tls-psk", 12) <= 0) {
1001+
errno = ENOKEY;
1002+
return -1;
1003+
}
1004+
if (version == 1) {
1005+
char hash_str[5];
1006+
1007+
sprintf(hash_str, "%02d ", cipher);
1008+
if (EVP_PKEY_CTX_add1_hkdf_info(ctx,
1009+
(const unsigned char *)hash_str,
1010+
strlen(hash_str)) <= 0) {
1011+
errno = ENOKEY;
1012+
return -1;
1013+
}
1014+
}
1015+
if (EVP_PKEY_CTX_add1_hkdf_info(ctx,
1016+
(const unsigned char *)context,
1017+
strlen(context)) <= 0) {
1018+
errno = ENOKEY;
1019+
return -1;
1020+
}
1021+
1022+
if (EVP_PKEY_derive(ctx, psk, &key_len) <= 0) {
1023+
errno = ENOKEY;
1024+
return -1;
1025+
}
1026+
1027+
return key_len;
1028+
}
1029+
8881030
static DEFINE_CLEANUP_FUNC(
8891031
cleanup_ossl_lib_ctx, OSSL_LIB_CTX *, OSSL_LIB_CTX_free)
8901032
#define _cleanup_ossl_lib_ctx_ __cleanup__(cleanup_ossl_lib_ctx)
@@ -1102,7 +1244,7 @@ static int gen_tls_identity(const char *hostnqn, const char *subsysnqn,
11021244
static int derive_nvme_keys(const char *hostnqn, const char *subsysnqn,
11031245
char *identity, int version,
11041246
int hmac, unsigned char *configured,
1105-
unsigned char *psk, int key_len)
1247+
unsigned char *psk, int key_len, bool compat)
11061248
{
11071249
_cleanup_free_ unsigned char *retained = NULL;
11081250
_cleanup_free_ char *digest = NULL;
@@ -1120,7 +1262,12 @@ static int derive_nvme_keys(const char *hostnqn, const char *subsysnqn,
11201262
errno = ENOMEM;
11211263
return -1;
11221264
}
1123-
ret = derive_retained_key(hmac, hostnqn, configured, retained, key_len);
1265+
if (compat)
1266+
ret = derive_retained_key_compat(hmac, hostnqn, configured,
1267+
retained, key_len);
1268+
else
1269+
ret = derive_retained_key(hmac, hostnqn, configured,
1270+
retained, key_len);
11241271
if (ret < 0)
11251272
return ret;
11261273

@@ -1148,6 +1295,9 @@ static int derive_nvme_keys(const char *hostnqn, const char *subsysnqn,
11481295
digest, identity);
11491296
if (ret < 0)
11501297
return ret;
1298+
if (compat)
1299+
return derive_tls_key_compat(version, cipher, context, retained,
1300+
psk, psk_len);
11511301
return derive_tls_key(version, cipher, context, retained,
11521302
psk, key_len);
11531303
}
@@ -1197,7 +1347,7 @@ char *nvme_generate_tls_key_identity(const char *hostnqn, const char *subsysnqn,
11971347

11981348
memset(psk, 0, key_len);
11991349
ret = derive_nvme_keys(hostnqn, subsysnqn, identity, version, hmac,
1200-
configured_key, psk, key_len);
1350+
configured_key, psk, key_len, false);
12011351
out_free_identity:
12021352
if (ret < 0) {
12031353
free(identity);
@@ -1365,10 +1515,11 @@ int nvme_scan_tls_keys(const char *keyring, nvme_scan_tls_keys_cb_t cb,
13651515
return ret;
13661516
}
13671517

1368-
static long __nvme_insert_tls_key_versioned(key_serial_t keyring_id, const char *key_type,
1369-
const char *hostnqn, const char *subsysnqn,
1370-
int version, int hmac,
1371-
unsigned char *configured_key, int key_len)
1518+
static long __nvme_insert_tls_key(key_serial_t keyring_id, const char *key_type,
1519+
const char *hostnqn, const char *subsysnqn,
1520+
int version, int hmac,
1521+
unsigned char *configured_key, int key_len,
1522+
bool compat)
13721523
{
13731524
_cleanup_free_ unsigned char *psk = NULL;
13741525
_cleanup_free_ char *identity = NULL;
@@ -1394,7 +1545,7 @@ static long __nvme_insert_tls_key_versioned(key_serial_t keyring_id, const char
13941545
}
13951546
memset(psk, 0, key_len);
13961547
ret = derive_nvme_keys(hostnqn, subsysnqn, identity, version, hmac,
1397-
configured_key, psk, key_len);
1548+
configured_key, psk, key_len, compat);
13981549
if (ret != key_len) {
13991550
errno = ENOKEY;
14001551
return 0;
@@ -1422,10 +1573,33 @@ long nvme_insert_tls_key_versioned(const char *keyring, const char *key_type,
14221573
ret = nvme_set_keyring(keyring_id);
14231574
if (ret < 0)
14241575
return 0;
1425-
return __nvme_insert_tls_key_versioned(keyring_id, key_type,
1426-
hostnqn, subsysnqn,
1427-
version, hmac,
1428-
configured_key, key_len);
1576+
return __nvme_insert_tls_key(keyring_id, key_type,
1577+
hostnqn, subsysnqn,
1578+
version, hmac,
1579+
configured_key, key_len, false);
1580+
}
1581+
1582+
long nvme_insert_tls_key_compat(const char *keyring, const char *key_type,
1583+
const char *hostnqn, const char *subsysnqn,
1584+
int version, int hmac,
1585+
unsigned char *configured_key, int key_len)
1586+
{
1587+
key_serial_t keyring_id;
1588+
int ret;
1589+
1590+
keyring_id = nvme_lookup_keyring(keyring);
1591+
if (keyring_id == 0) {
1592+
errno = ENOKEY;
1593+
return 0;
1594+
}
1595+
1596+
ret = nvme_set_keyring(keyring_id);
1597+
if (ret < 0)
1598+
return 0;
1599+
return __nvme_insert_tls_key(keyring_id, key_type,
1600+
hostnqn, subsysnqn,
1601+
version, hmac,
1602+
configured_key, key_len, true);
14291603
}
14301604

14311605
long nvme_revoke_tls_key(const char *keyring, const char *key_type,
@@ -1447,7 +1621,7 @@ long nvme_revoke_tls_key(const char *keyring, const char *key_type,
14471621
return keyctl_revoke(key);
14481622
}
14491623

1450-
static long __nvme_insert_tls_key(long keyring_id,
1624+
static long __nvme_import_tls_key(long keyring_id,
14511625
const char *hostnqn, const char *subsysnqn,
14521626
const char *identity, const char *key)
14531627
{
@@ -1468,10 +1642,10 @@ static long __nvme_insert_tls_key(long keyring_id,
14681642
* configured key. Derive a new key and load the newly
14691643
* created key into the keystore.
14701644
*/
1471-
return __nvme_insert_tls_key_versioned(keyring_id, "psk",
1472-
hostnqn, subsysnqn,
1473-
version, hmac,
1474-
key_data, key_len);
1645+
return __nvme_insert_tls_key(keyring_id, "psk",
1646+
hostnqn, subsysnqn,
1647+
version, hmac,
1648+
key_data, key_len, false);
14751649
}
14761650

14771651
return nvme_update_key(keyring_id, "psk", identity,
@@ -1526,7 +1700,7 @@ int __nvme_import_keys_from_config(nvme_host_t h, nvme_ctrl_t c,
15261700
id = nvme_lookup_key("psk", identity);
15271701

15281702
if (!id)
1529-
id = __nvme_insert_tls_key(kr_id, hostnqn,
1703+
id = __nvme_import_tls_key(kr_id, hostnqn,
15301704
subsysnqn, identity, key);
15311705

15321706
if (id <= 0) {

src/nvme/linux.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,32 @@ long nvme_insert_tls_key_versioned(const char *keyring, const char *key_type,
400400
int version, int hmac,
401401
unsigned char *configured_key, int key_len);
402402

403+
/**
404+
* nvme_insert_tls_key_compat() - Derive and insert TLS key (compability mode)
405+
* @keyring: Keyring to use
406+
* @key_type: Type of the resulting key
407+
* @hostnqn: Host NVMe Qualified Name
408+
* @subsysnqn: Subsystem NVMe Qualified Name
409+
* @version: Key version to use
410+
* @hmac: HMAC algorithm
411+
* @configured_key: Configured key data to derive the key from
412+
* @key_len: Length of @configured_key
413+
*
414+
* Derives a 'retained' TLS key as specified in NVMe TCP 1.0a (if
415+
* @version s set to '0') or NVMe TP8028 (if @version is set to '1) and
416+
* stores it as type @key_type in the keyring specified by @keyring.
417+
* This version differs from @nvme_insert_tls_key_versioned() in that it
418+
* uses the original implementation for HKDF Expand-Label which does not
419+
* prefix the 'info' and 'label' strings with the length.
420+
*
421+
* Return: The key serial number if the key could be inserted into
422+
* the keyring or 0 with errno otherwise.
423+
*/
424+
long nvme_insert_tls_key_compat(const char *keyring, const char *key_type,
425+
const char *hostnqn, const char *subsysnqn,
426+
int version, int hmac,
427+
unsigned char *configured_key, int key_len);
428+
403429
/**
404430
* nvme_generate_tls_key_identity() - Generate the TLS key identity
405431
* @hostnqn: Host NVMe Qualified Name

0 commit comments

Comments
 (0)