Skip to content

Commit 454373a

Browse files
dwsuseigaw
authored andcommitted
linux: add import/export function for TLS pre-shared keys
The existing import/export function do not handle different version of the interchange format nor do the handle the HMAC independent of the version. Thus allow the caller to select version and HMAC independently when exporting resp. importing. This makes this interface also future proof when new HMAC or key lengths are added to the spec. The pre-shared key interchange format also has 'no transform' option when the configured key should be used as retained key. Signed-off-by: Daniel Wagner <[email protected]>
1 parent 97c100a commit 454373a

3 files changed

Lines changed: 143 additions & 28 deletions

File tree

src/libnvme.map

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
11
# SPDX-License-Identifier: LGPL-2.1-or-later
2+
LIBNVME_1.11 {
3+
global:
4+
nvme_export_tls_key_versioned;
5+
nvme_import_tls_key_versioned;
6+
};
7+
8+
29
LIBNVME_1.10 {
310
global:
411
nvme_free_uri;

src/nvme/linux.c

Lines changed: 99 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1499,21 +1499,44 @@ long nvme_insert_tls_key(const char *keyring, const char *key_type,
14991499
configured_key, key_len);
15001500
}
15011501

1502-
char *nvme_export_tls_key(const unsigned char *key_data, int key_len)
1502+
/*
1503+
* PSK Interchange Format
1504+
* NVMeTLSkey-<v>:<xx>:<s>:
1505+
*
1506+
* x: version as one ASCII char
1507+
* yy: hmac encoded as two ASCII chars
1508+
* 00: no transform ('configured PSK')
1509+
* 01: SHA-256
1510+
* 02: SHA-384
1511+
* s: 32 or 48 bytes binary followed by a CRC-32 of the configured PSK
1512+
* (4 bytes) encoded as base64
1513+
*/
1514+
char *nvme_export_tls_key_versioned(unsigned char version, unsigned char hmac,
1515+
const unsigned char *key_data,
1516+
size_t key_len)
15031517
{
15041518
unsigned int raw_len, encoded_len, len;
15051519
unsigned long crc = crc32(0L, NULL, 0);
15061520
unsigned char raw_secret[52];
15071521
char *encoded_key;
15081522

1509-
if (key_len == 32) {
1510-
raw_len = 32;
1511-
} else if (key_len == 48) {
1512-
raw_len = 48;
1513-
} else {
1514-
errno = EINVAL;
1515-
return NULL;
1523+
switch (hmac) {
1524+
case NVME_HMAC_ALG_NONE:
1525+
if (key_len != 32 && key_len != 48)
1526+
goto err_inval;
1527+
break;
1528+
case NVME_HMAC_ALG_SHA2_256:
1529+
if (key_len != 32)
1530+
goto err_inval;
1531+
break;
1532+
case NVME_HMAC_ALG_SHA2_384:
1533+
if (key_len != 48)
1534+
goto err_inval;
1535+
break;
1536+
default:
1537+
goto err_inval;
15161538
}
1539+
raw_len = key_len;
15171540

15181541
memcpy(raw_secret, key_data, raw_len);
15191542
crc = crc32(crc, raw_secret, raw_len);
@@ -1529,48 +1552,75 @@ char *nvme_export_tls_key(const unsigned char *key_data, int key_len)
15291552
return NULL;
15301553
}
15311554
memset(encoded_key, 0, encoded_len);
1532-
len = sprintf(encoded_key, "NVMeTLSkey-1:%02x:",
1533-
key_len == 32 ? 1 : 2);
1555+
len = sprintf(encoded_key, "NVMeTLSkey-%x:%02x:", version, hmac);
15341556
len += base64_encode(raw_secret, raw_len, encoded_key + len);
15351557
encoded_key[len++] = ':';
15361558
encoded_key[len++] = '\0';
15371559

15381560
return encoded_key;
1561+
1562+
err_inval:
1563+
errno = EINVAL;
1564+
return NULL;
1565+
15391566
}
15401567

1541-
unsigned char *nvme_import_tls_key(const char *encoded_key, int *key_len,
1542-
unsigned int *hmac)
1568+
char *nvme_export_tls_key(const unsigned char *key_data, int key_len)
1569+
{
1570+
unsigned char hmac;
1571+
1572+
if (key_len == 32)
1573+
hmac = NVME_HMAC_ALG_SHA2_256;
1574+
else
1575+
hmac = NVME_HMAC_ALG_SHA2_384;
1576+
1577+
return nvme_export_tls_key_versioned(1, hmac, key_data, key_len);
1578+
}
1579+
1580+
unsigned char *nvme_import_tls_key_versioned(const char *encoded_key,
1581+
unsigned char *version,
1582+
unsigned char *hmac,
1583+
size_t *key_len)
15431584
{
15441585
unsigned char decoded_key[128], *key_data;
15451586
unsigned int crc = crc32(0L, NULL, 0);
15461587
unsigned int key_crc;
1547-
int err, decoded_len;
1588+
int err, _version, _hmac, decoded_len;
1589+
size_t len;
15481590

1549-
if (sscanf(encoded_key, "NVMeTLSkey-1:%02x:*s", &err) != 1) {
1591+
if (sscanf(encoded_key, "NVMeTLSkey-%d:%02x:*s",
1592+
&_version, &_hmac) != 2) {
15501593
errno = EINVAL;
15511594
return NULL;
15521595
}
1553-
switch (err) {
1554-
case 1:
1555-
if (strlen(encoded_key) != 65) {
1556-
errno = EINVAL;
1557-
return NULL;
1558-
}
1596+
1597+
if (_version != 1) {
1598+
errno = EINVAL;
1599+
return NULL;
1600+
}
1601+
*version = _version;
1602+
1603+
len = strlen(encoded_key);
1604+
switch (_hmac) {
1605+
case NVME_HMAC_ALG_NONE:
1606+
if (len != 65 && len != 89)
1607+
goto err_inval;
15591608
break;
1560-
case 2:
1561-
if (strlen(encoded_key) != 89) {
1562-
errno = EINVAL;
1563-
return NULL;
1564-
}
1609+
case NVME_HMAC_ALG_SHA2_256:
1610+
if (len != 65)
1611+
goto err_inval;
1612+
break;
1613+
case NVME_HMAC_ALG_SHA2_384:
1614+
if (len != 89)
1615+
goto err_inval;
15651616
break;
15661617
default:
15671618
errno = EINVAL;
15681619
return NULL;
15691620
}
1621+
*hmac = _hmac;
15701622

1571-
*hmac = err;
1572-
err = base64_decode(encoded_key + 16, strlen(encoded_key) - 17,
1573-
decoded_key);
1623+
err = base64_decode(encoded_key + 16, len - 17, decoded_key);
15741624
if (err < 0) {
15751625
errno = ENOKEY;
15761626
return NULL;
@@ -1602,4 +1652,25 @@ unsigned char *nvme_import_tls_key(const char *encoded_key, int *key_len,
16021652

16031653
*key_len = decoded_len;
16041654
return key_data;
1655+
1656+
err_inval:
1657+
errno = EINVAL;
1658+
return NULL;
1659+
}
1660+
1661+
unsigned char *nvme_import_tls_key(const char *encoded_key, int *key_len,
1662+
unsigned int *hmac)
1663+
{
1664+
unsigned char version, _hmac;
1665+
unsigned char *psk;
1666+
size_t len;
1667+
1668+
psk = nvme_import_tls_key_versioned(encoded_key, &version,
1669+
&_hmac, &len);
1670+
if (!psk)
1671+
return NULL;
1672+
1673+
*hmac = _hmac;
1674+
*key_len = len;
1675+
return psk;
16051676
}

src/nvme/linux.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,25 @@ long nvme_revoke_tls_key(const char *keyring, const char *key_type,
436436
*/
437437
char *nvme_export_tls_key(const unsigned char *key_data, int key_len);
438438

439+
/**
440+
* nvme_export_tls_key_versioned() - Export a TLS pre-shared key
441+
* @version: Indicated the representation of the TLS PSK
442+
* @hmac: HMAC algorithm used to transfor the configured PSK
443+
* in a retained PSK
444+
* @key_data: Raw data of the key
445+
* @key_len: Length of @key_data
446+
*
447+
* Returns @key_data in the PSK Interchange format as defined in section
448+
* 3.6.1.5 of the NVMe TCP Transport specification.
449+
*
450+
* Return: The string containing the TLS identity or NULL with errno set
451+
* on error. It is the responsibility of the caller to free the returned
452+
* string.
453+
*/
454+
char *nvme_export_tls_key_versioned(unsigned char version, unsigned char hmac,
455+
const unsigned char *key_data,
456+
size_t key_len);
457+
439458
/**
440459
* nvme_import_tls_key() - Import a TLS key
441460
* @encoded_key: TLS key in PSK interchange format
@@ -451,6 +470,24 @@ char *nvme_export_tls_key(const unsigned char *key_data, int key_len);
451470
unsigned char *nvme_import_tls_key(const char *encoded_key, int *key_len,
452471
unsigned int *hmac);
453472

473+
/**
474+
* nvme_import_tls_key_versioned() - Import a TLS key
475+
* @encoded_key: TLS key in PSK interchange format
476+
* @version: Indicated the representation of the TLS PSK
477+
* @hmac: HMAC algorithm used to transfor the configured
478+
* PSK in a retained PSK
479+
* @key_len: Length of the resulting key data
480+
*
481+
* Imports @key_data in the PSK Interchange format as defined in section
482+
* 3.6.1.5 of the NVMe TCP Transport specification.
483+
*
484+
* Return: The raw data of the PSK or NULL with errno set on error. It is
485+
* the responsibility of the caller to free the returned string.
486+
*/
487+
unsigned char *nvme_import_tls_key_versioned(const char *encoded_key,
488+
unsigned char *version,
489+
unsigned char *hmac,
490+
size_t *key_len);
454491
/**
455492
* nvme_submit_passthru - Low level ioctl wrapper for passthru commands
456493
* @fd: File descriptor of the nvme device

0 commit comments

Comments
 (0)