Skip to content

Commit dc6fc7b

Browse files
committed
libnvme: support NVMe TLS identities version 1
With NVMe TP8018 a new version '1' for generating NVMe TLS identities was specified; identities generated for this version require a PSK hash to be attached to the version '0' identifier. This patch implements a new function 'nvme_insert_tls_keys_versioned()' to support this functionality and makes the original function 'nvme_insert_tls_keys()' a wrapper for the new function. Signed-off-by: Hannes Reinecke <[email protected]>
1 parent 31b6231 commit dc6fc7b

3 files changed

Lines changed: 275 additions & 20 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_1_7 {
33
global:
44
nvme_init_copy_range_f2;
55
nvme_init_copy_range_f3;
6+
nvme_insert_tls_key_versioned;
67
};
78

89
LIBNVME_1_6 {

src/nvme/linux.c

Lines changed: 251 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include "tree.h"
4040
#include "log.h"
4141
#include "private.h"
42+
#include "base64.h"
4243

4344
static int __nvme_open(const char *name)
4445
{
@@ -554,11 +555,17 @@ static int derive_retained_key(int hmac, const char *hostnqn,
554555
}
555556

556557
static int gen_tls_identity(const char *hostnqn, const char *subsysnqn,
557-
int hmac, char *identity,
558+
int version, int hmac, char *identity,
558559
unsigned char *retained, size_t key_len)
559560
{
561+
if (version != 0) {
562+
nvme_msg(NULL, LOG_ERR, "NVMe TLS 2.0 is not supported; "
563+
"recompile with OpenSSL support.\n");
564+
errno = NOTSUP;
565+
return -1;
566+
}
560567
sprintf(identity, "NVMe0R%02d %s %s",
561-
version, hmac, hostnqn, subsysnqn);
568+
hmac, hostnqn, subsysnqn);
562569
return strlen(identity);
563570
}
564571

@@ -780,12 +787,90 @@ int nvme_gen_dhchap_key(char *hostnqn, enum nvme_hmac_alg hmac,
780787
}
781788

782789
static int gen_tls_identity(const char *hostnqn, const char *subsysnqn,
783-
int hmac, char *identity,
790+
int version, int hmac, char *identity,
784791
unsigned char *retained, size_t key_len)
785792
{
786-
sprintf(identity, "NVMe0R%02d %s %s",
787-
hmac, hostnqn, subsysnqn);
788-
return strlen(identity);
793+
static const char hmac_seed[] = "NVMe-over-Fabrics";
794+
size_t hmac_len;
795+
const EVP_MD *md = select_hmac(hmac, &hmac_len);
796+
HMAC_CTX *hmac_ctx;
797+
unsigned char *psk_ctx;
798+
char *enc_ctx;
799+
size_t len = -1;
800+
801+
if (version == 0) {
802+
sprintf(identity, "NVMe%01dR%02d %s %s",
803+
version, hmac, hostnqn, subsysnqn);
804+
return strlen(identity);
805+
}
806+
if (version > 1) {
807+
errno = EINVAL;
808+
return -1;
809+
}
810+
811+
hmac_ctx = HMAC_CTX_new();
812+
if (!hmac_ctx) {
813+
errno = ENOMEM;
814+
return -1;
815+
}
816+
if (!md) {
817+
errno = EINVAL;
818+
goto out_free_hmac;
819+
}
820+
821+
psk_ctx = malloc(key_len);
822+
if (!psk_ctx) {
823+
errno = ENOMEM;
824+
goto out_free_hmac;
825+
}
826+
if (!HMAC_Init_ex(hmac_ctx, retained, key_len, md, NULL)) {
827+
errno = ENOMEM;
828+
goto out_free_psk;
829+
}
830+
if (!HMAC_Update(hmac_ctx, (unsigned char *)hostnqn,
831+
strlen(hostnqn))) {
832+
errno = ENOKEY;
833+
goto out_free_psk;
834+
}
835+
if (!HMAC_Update(hmac_ctx, (unsigned char *)" ", 1)) {
836+
errno = ENOKEY;
837+
goto out_free_psk;
838+
}
839+
if (!HMAC_Update(hmac_ctx, (unsigned char *)subsysnqn,
840+
strlen(subsysnqn))) {
841+
errno = ENOKEY;
842+
goto out_free_psk;
843+
}
844+
if (!HMAC_Update(hmac_ctx, (unsigned char *)" ", 1)) {
845+
errno = ENOKEY;
846+
goto out_free_psk;
847+
}
848+
if (!HMAC_Update(hmac_ctx, (unsigned char *)hmac_seed,
849+
strlen(hmac_seed))) {
850+
errno = ENOKEY;
851+
goto out_free_psk;
852+
}
853+
if (!HMAC_Final(hmac_ctx, psk_ctx, (unsigned int *)&key_len)) {
854+
errno = ENOKEY;
855+
goto out_free_psk;
856+
}
857+
enc_ctx = malloc(key_len * 2);
858+
memset(enc_ctx, 0, key_len * 2);
859+
len = base64_encode(psk_ctx, key_len, enc_ctx);
860+
if (len < 0) {
861+
errno = ENOKEY;
862+
goto out_free_enc;
863+
}
864+
sprintf(identity, "NVMe%01dR%02d %s %s %s",
865+
version, hmac, hostnqn, subsysnqn, enc_ctx);
866+
len = strlen(identity);
867+
out_free_enc:
868+
free(enc_ctx);
869+
out_free_psk:
870+
free(psk_ctx);
871+
out_free_hmac:
872+
HMAC_CTX_free(hmac_ctx);
873+
return len;
789874
}
790875
#endif /* !CONFIG_OPENSSL_1 */
791876

@@ -883,18 +968,133 @@ int nvme_gen_dhchap_key(char *hostnqn, enum nvme_hmac_alg hmac,
883968
}
884969

885970
static int gen_tls_identity(const char *hostnqn, const char *subsysnqn,
886-
int hmac, char *identity,
971+
int version, int hmac, char *identity,
887972
unsigned char *retained, size_t key_len)
888973
{
889-
sprintf(identity, "NVMe0R%02d %s %s",
890-
version, hmac, hostnqn, subsysnqn);
891-
return strlen(identity);
974+
static const char hmac_seed[] = "NVMe-over-Fabrics";
975+
size_t hmac_len;
976+
OSSL_PARAM params[2], *p = params;
977+
OSSL_LIB_CTX *lib_ctx;
978+
EVP_MAC_CTX *mac_ctx = NULL;
979+
EVP_MAC *mac = NULL;
980+
char *progq = NULL;
981+
char *digest = NULL;
982+
unsigned char *psk_ctx;
983+
char *enc_ctx;
984+
size_t len = -1;
985+
986+
if (version == 0) {
987+
sprintf(identity, "NVMe%01dR%02d %s %s",
988+
version, hmac, hostnqn, subsysnqn);
989+
return strlen(identity);
990+
}
991+
if (version > 1) {
992+
errno = EINVAL;
993+
return -1;
994+
}
995+
996+
lib_ctx = OSSL_LIB_CTX_new();
997+
if (!lib_ctx) {
998+
errno = ENOMEM;
999+
return -1;
1000+
}
1001+
mac = EVP_MAC_fetch(lib_ctx, OSSL_MAC_NAME_HMAC, progq);
1002+
if (!mac) {
1003+
errno = ENOMEM;
1004+
goto out_free_ossl;
1005+
}
1006+
1007+
mac_ctx = EVP_MAC_CTX_new(mac);
1008+
if (!mac_ctx) {
1009+
errno = ENOMEM;
1010+
goto out_free_mac;
1011+
}
1012+
switch (hmac) {
1013+
case NVME_HMAC_ALG_SHA2_256:
1014+
digest = OSSL_DIGEST_NAME_SHA2_256;
1015+
break;
1016+
case NVME_HMAC_ALG_SHA2_384:
1017+
digest = OSSL_DIGEST_NAME_SHA2_384;
1018+
break;
1019+
default:
1020+
errno = EINVAL;
1021+
break;
1022+
}
1023+
if (!digest)
1024+
goto out_free_ctx;
1025+
*p++ = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_DIGEST,
1026+
digest, 0);
1027+
*p = OSSL_PARAM_construct_end();
1028+
1029+
psk_ctx = malloc(key_len);
1030+
if (!psk_ctx) {
1031+
errno = ENOMEM;
1032+
goto out_free_ctx;
1033+
}
1034+
1035+
if (!EVP_MAC_init(mac_ctx, retained, key_len, params)) {
1036+
errno = ENOKEY;
1037+
goto out_free_psk;
1038+
}
1039+
if (!EVP_MAC_update(mac_ctx, (unsigned char *)hostnqn,
1040+
strlen(hostnqn))) {
1041+
errno = ENOKEY;
1042+
goto out_free_psk;
1043+
}
1044+
if (!EVP_MAC_update(mac_ctx, (unsigned char *)" ", 1)) {
1045+
errno = ENOKEY;
1046+
goto out_free_psk;
1047+
}
1048+
if (!EVP_MAC_update(mac_ctx, (unsigned char *)subsysnqn,
1049+
strlen(subsysnqn))) {
1050+
errno = ENOKEY;
1051+
goto out_free_psk;
1052+
}
1053+
if (!EVP_MAC_update(mac_ctx, (unsigned char *)" ", 1)) {
1054+
errno = ENOKEY;
1055+
goto out_free_psk;
1056+
}
1057+
if (!EVP_MAC_update(mac_ctx, (unsigned char *)hmac_seed,
1058+
strlen(hmac_seed))) {
1059+
errno = ENOKEY;
1060+
goto out_free_psk;
1061+
}
1062+
if (!EVP_MAC_final(mac_ctx, psk_ctx, &hmac_len, key_len)) {
1063+
errno = ENOKEY;
1064+
goto out_free_psk;
1065+
}
1066+
if (hmac_len > key_len) {
1067+
errno = EMSGSIZE;
1068+
goto out_free_psk;
1069+
}
1070+
enc_ctx = malloc(hmac_len * 2);
1071+
memset(enc_ctx, 0, hmac_len * 2);
1072+
len = base64_encode(psk_ctx, hmac_len, enc_ctx);
1073+
if (len < 0) {
1074+
errno = ENOKEY;
1075+
goto out_free_enc;
1076+
}
1077+
sprintf(identity, "NVMe%01dR%02d %s %s %s",
1078+
version, hmac, hostnqn, subsysnqn, enc_ctx);
1079+
len = strlen(identity);
1080+
out_free_enc:
1081+
free(enc_ctx);
1082+
out_free_psk:
1083+
free(psk_ctx);
1084+
out_free_ctx:
1085+
EVP_MAC_CTX_free(mac_ctx);
1086+
out_free_mac:
1087+
EVP_MAC_free(mac);
1088+
out_free_ossl:
1089+
OSSL_LIB_CTX_free(lib_ctx);
1090+
1091+
return len;
8921092
}
8931093
#endif /* !CONFIG_OPENSSL_3 */
8941094

8951095
#ifdef CONFIG_KEYUTILS
8961096
static int derive_nvme_keys(const char *hostnqn, const char *subsysnqn,
897-
char *identity,
1097+
char *identity, int version,
8981098
int hmac, unsigned char *configured,
8991099
unsigned char *psk, int key_len)
9001100
{
@@ -914,7 +1114,7 @@ static int derive_nvme_keys(const char *hostnqn, const char *subsysnqn,
9141114
ret = derive_retained_key(hmac, hostnqn, configured, retained, key_len);
9151115
if (ret < 0)
9161116
goto out;
917-
ret = gen_tls_identity(hostnqn, subsysnqn, hmac,
1117+
ret = gen_tls_identity(hostnqn, subsysnqn, version, hmac,
9181118
identity, retained, key_len);
9191119
if (ret < 0)
9201120
goto out;
@@ -924,6 +1124,23 @@ static int derive_nvme_keys(const char *hostnqn, const char *subsysnqn,
9241124
return ret;
9251125
}
9261126

1127+
static size_t nvme_identity_len(int hmac, int version, const char *hostnqn,
1128+
const char *subsysnqn)
1129+
{
1130+
size_t len;
1131+
1132+
len = strlen(hostnqn) + strlen(subsysnqn) + 12;
1133+
if (version == 1) {
1134+
len += 66;
1135+
if (hmac == NVME_HMAC_ALG_SHA2_384)
1136+
len += 32;
1137+
} else if (version > 1) {
1138+
errno = EINVAL;
1139+
return -1;
1140+
}
1141+
return len;
1142+
}
1143+
9271144
long nvme_lookup_keyring(const char *keyring)
9281145
{
9291146
key_serial_t keyring_id;
@@ -963,9 +1180,10 @@ int nvme_set_keyring(long key_id)
9631180
return 0;
9641181
}
9651182

966-
long nvme_insert_tls_key(const char *keyring, const char *key_type,
967-
const char *hostnqn, const char *subsysnqn, int hmac,
968-
unsigned char *configured_key, int key_len)
1183+
long nvme_insert_tls_key_versioned(const char *keyring, const char *key_type,
1184+
const char *hostnqn, const char *subsysnqn,
1185+
int version, int hmac,
1186+
unsigned char *configured_key, int key_len)
9691187
{
9701188
key_serial_t keyring_id, key = 0;
9711189
char *identity;
@@ -977,7 +1195,10 @@ long nvme_insert_tls_key(const char *keyring, const char *key_type,
9771195
if (keyring_id == 0)
9781196
return -1;
9791197

980-
identity_len = strlen(hostnqn) + strlen(subsysnqn) + 12;
1198+
identity_len = nvme_identity_len(hmac, version, hostnqn, subsysnqn);
1199+
if (identity_len < 0)
1200+
return -1;
1201+
9811202
identity = malloc(identity_len);
9821203
if (!identity) {
9831204
errno = ENOMEM;
@@ -990,7 +1211,7 @@ long nvme_insert_tls_key(const char *keyring, const char *key_type,
9901211
goto out_free_identity;
9911212
}
9921213
memset(psk, 0, key_len);
993-
ret = derive_nvme_keys(hostnqn, subsysnqn, identity, hmac,
1214+
ret = derive_nvme_keys(hostnqn, subsysnqn, identity, version, hmac,
9941215
configured_key, psk, key_len);
9951216
if (ret != key_len)
9961217
goto out_free_psk;
@@ -1045,13 +1266,23 @@ int nvme_set_keyring(long key_id)
10451266
return -1;
10461267
}
10471268

1048-
long nvme_insert_tls_key(const char *keyring, const char *key_type,
1049-
const char *hostnqn, const char *subsysnqn, int hmac,
1050-
unsigned char *configured_key, int key_len)
1269+
long nvme_insert_tls_key_versioned(const char *keyring, const char *key_type,
1270+
const char *hostnqn, const char *subsysnqn,
1271+
int version, int hmac,
1272+
unsigned char *configured_key, int key_len)
10511273
{
10521274
nvme_msg(NULL, LOG_ERR, "key operations not supported; "
10531275
"recompile with keyutils support.\n");
10541276
errno = ENOTSUP;
10551277
return -1;
10561278
}
10571279
#endif
1280+
1281+
long nvme_insert_tls_key(const char *keyring, const char *key_type,
1282+
const char *hostnqn, const char *subsysnqn, int hmac,
1283+
unsigned char *configured_key, int key_len)
1284+
{
1285+
return nvme_insert_tls_key_versioned(keyring, key_type,
1286+
hostnqn, subsysnqn, 0, hmac,
1287+
configured_key, key_len);
1288+
}

src/nvme/linux.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,4 +293,27 @@ long nvme_insert_tls_key(const char *keyring, const char *key_type,
293293
const char *hostnqn, const char *subsysnqn, int hmac,
294294
unsigned char *configured_key, int key_len);
295295

296+
/**
297+
* nvme_insert_tls_key_versioned() - Derive and insert TLS key
298+
* @keyring: Keyring to use
299+
* @key_type: Type of the resulting key
300+
* @hostnqn: Host NVMe Qualified Name
301+
* @subsysnqn: Subsystem NVMe Qualified Name
302+
* @version: Key version to use
303+
* @hmac: HMAC algorithm
304+
* @configured_key: Configured key data to derive the key from
305+
* @key_len: Length of @configured_key
306+
*
307+
* Derives a 'retained' TLS key as specified in NVMe TCP 1.0a (if
308+
* @version s set to '0') or NVMe TP8028 (if @version is set to '1) and
309+
* stores it as type @key_type in the keyring specified by @keyring.
310+
*
311+
* Return: The key serial number if the key could be inserted into
312+
* the keyring or 0 with errno otherwise.
313+
*/
314+
long nvme_insert_tls_key_versioned(const char *keyring, const char *key_type,
315+
const char *hostnqn, const char *subsysnqn,
316+
int version, int hmac,
317+
unsigned char *configured_key, int key_len);
318+
296319
#endif /* _LIBNVME_LINUX_H */

0 commit comments

Comments
 (0)