Skip to content

Commit af874a2

Browse files
hreineckeigaw
authored andcommitted
nvme: add 'nvme_insert_tls_key()' function
Add a function to derive a TLS key and insert it into the given keyring. Signed-off-by: Hannes Reinecke <[email protected]> [dwagner: updated doc to mention errno set if failure] Signed-off-by: Daniel Wagner <[email protected]>
1 parent b707ef2 commit af874a2

3 files changed

Lines changed: 216 additions & 1 deletion

File tree

src/libnvme.map

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

89
LIBNVME_1_3 {

src/nvme/linux.c

Lines changed: 195 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <openssl/engine.h>
2222
#include <openssl/evp.h>
2323
#include <openssl/hmac.h>
24+
#include <openssl/kdf.h>
2425

2526
#ifdef CONFIG_OPENSSL_3
2627
#include <openssl/core_names.h>
@@ -474,7 +475,143 @@ int nvme_gen_dhchap_key(char *hostnqn, enum nvme_hmac_alg hmac,
474475
memcpy(key, secret, key_len);
475476
return 0;
476477
}
477-
#endif /* !CONFIG_OPENSSL */
478+
479+
static int derive_nvme_keys(const char *hostnqn, const char *identity,
480+
int hmac, unsigned char *configured,
481+
unsigned char *psk, int key_len)
482+
{
483+
errno = EOPNOTSUPP;
484+
return -1;
485+
}
486+
#else /* CONFIG_OPENSSL */
487+
static int derive_retained_key(const EVP_MD *md, const char *hostnqn,
488+
unsigned char *generated,
489+
unsigned char *retained,
490+
size_t key_len)
491+
{
492+
EVP_PKEY_CTX *ctx;
493+
int ret;
494+
495+
ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
496+
if (!ctx) {
497+
errno = ENOMEM;
498+
return -1;
499+
}
500+
501+
if (EVP_PKEY_derive_init(ctx) <= 0) {
502+
ret = -ENOMEM;
503+
goto out_free_ctx;
504+
}
505+
ret = -ENOKEY;
506+
if (EVP_PKEY_CTX_set_hkdf_md(ctx, md) <= 0)
507+
goto out_free_ctx;
508+
if (EVP_PKEY_CTX_set1_hkdf_key(ctx, generated, key_len) <= 0)
509+
goto out_free_ctx;
510+
if (EVP_PKEY_CTX_add1_hkdf_info(ctx,
511+
(const unsigned char *)"tls13 ", 6) <= 0)
512+
goto out_free_ctx;
513+
if (EVP_PKEY_CTX_add1_hkdf_info(ctx,
514+
(const unsigned char *)"HostNQN", 7) <= 0)
515+
goto out_free_ctx;
516+
if (EVP_PKEY_CTX_add1_hkdf_info(ctx,
517+
(const unsigned char *)hostnqn, strlen(hostnqn)) <= 0)
518+
goto out_free_ctx;
519+
520+
if (EVP_PKEY_derive(ctx, retained, &key_len) > 0)
521+
ret = key_len;
522+
523+
out_free_ctx:
524+
if (ret < 0) {
525+
errno = -ret;
526+
ret = -1;
527+
}
528+
EVP_PKEY_CTX_free(ctx);
529+
return ret;
530+
}
531+
532+
static int derive_tls_key(const EVP_MD *md, const char *identity,
533+
unsigned char *retained,
534+
unsigned char *psk, size_t key_len)
535+
{
536+
EVP_PKEY_CTX *ctx;
537+
int ret;
538+
539+
ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
540+
if (!ctx) {
541+
errno = ENOMEM;
542+
return -1;
543+
}
544+
545+
if (EVP_PKEY_derive_init(ctx) <= 0) {
546+
ret = -ENOMEM;
547+
goto out_free_ctx;
548+
}
549+
ret = -ENOKEY;
550+
if (EVP_PKEY_CTX_set_hkdf_md(ctx, md) <= 0)
551+
goto out_free_ctx;
552+
if (EVP_PKEY_CTX_set1_hkdf_key(ctx, retained, key_len) <= 0)
553+
goto out_free_ctx;
554+
if (EVP_PKEY_CTX_add1_hkdf_info(ctx,
555+
(const unsigned char *)"tls13 ", 6) <= 0)
556+
goto out_free_ctx;
557+
if (EVP_PKEY_CTX_add1_hkdf_info(ctx,
558+
(const unsigned char *)"nvme-tls-psk", 12) <= 0)
559+
goto out_free_ctx;
560+
if (EVP_PKEY_CTX_add1_hkdf_info(ctx,
561+
(const unsigned char *)identity,
562+
strlen(identity)) <= 0)
563+
goto out_free_ctx;
564+
565+
if (EVP_PKEY_derive(ctx, psk, &key_len) > 0)
566+
ret = key_len;
567+
568+
out_free_ctx:
569+
EVP_PKEY_CTX_free(ctx);
570+
if (ret < 0) {
571+
errno = -ret;
572+
ret = -1;
573+
}
574+
575+
return ret;
576+
}
577+
578+
static int derive_nvme_keys(const char *hostnqn, const char *identity,
579+
int hmac, unsigned char *configured,
580+
unsigned char *psk, int key_len)
581+
{
582+
const EVP_MD *md;
583+
unsigned char *retained;
584+
int ret = -1;
585+
586+
if (!hostnqn || !identity) {
587+
errno = EINVAL;
588+
return -1;
589+
}
590+
591+
switch (hmac) {
592+
case 1:
593+
md = EVP_sha256();
594+
break;
595+
case 2:
596+
md = EVP_sha384();
597+
break;
598+
default:
599+
errno = EINVAL;
600+
return -1;
601+
}
602+
603+
retained = malloc(key_len);
604+
if (!retained) {
605+
errno = ENOMEM;
606+
return -1;
607+
}
608+
ret = derive_retained_key(md, hostnqn, configured, retained, key_len);
609+
if (ret > 0)
610+
ret = derive_tls_key(md, identity, retained, psk, key_len);
611+
free(retained);
612+
return ret;
613+
}
614+
#endif /* CONFIG_OPENSSL */
478615

479616
#ifdef CONFIG_OPENSSL_1
480617
int nvme_gen_dhchap_key(char *hostnqn, enum nvme_hmac_alg hmac,
@@ -653,6 +790,56 @@ long nvme_lookup_keyring(const char *keyring)
653790
return 0;
654791
return keyring_id;
655792
}
793+
794+
long nvme_insert_tls_key(const char *keyring, const char *key_type,
795+
const char *hostnqn, const char *subsysnqn, int hmac,
796+
unsigned char *configured_key, int key_len)
797+
{
798+
key_serial_t keyring_id, key = 0;
799+
char *identity;
800+
unsigned char *psk;
801+
int ret = -1;
802+
803+
keyring_id = nvme_lookup_keyring(keyring);
804+
if (keyring_id < 0)
805+
return -1;
806+
807+
identity = malloc(strlen(hostnqn) + strlen(subsysnqn) + 12);
808+
if (!identity) {
809+
errno = ENOMEM;
810+
return -1;
811+
}
812+
813+
sprintf(identity, "NVMe0R%02d %s %s", hmac, hostnqn, subsysnqn);
814+
815+
psk = malloc(key_len);
816+
if (!psk) {
817+
errno = ENOMEM;
818+
goto out_free_identity;
819+
}
820+
memset(psk, 0, key_len);
821+
ret = derive_nvme_keys(hostnqn, identity, hmac,
822+
configured_key, psk, key_len);
823+
if (ret != key_len)
824+
goto out_free_psk;
825+
826+
key = keyctl_search(keyring_id, key_type, identity, 0);
827+
if (key > 0) {
828+
if (keyctl_update(key, psk, key_len) < 0)
829+
key = 0;
830+
} else {
831+
key = add_key(key_type, identity,
832+
psk, key_len, keyring_id);
833+
if (key < 0)
834+
key = 0;
835+
}
836+
out_free_psk:
837+
free(psk);
838+
out_free_identity:
839+
free(identity);
840+
return key;
841+
}
842+
656843
#else
657844
long nvme_lookup_keyring(const char *keyring)
658845
{
@@ -661,4 +848,11 @@ long nvme_lookup_keyring(const char *keyring)
661848
errno = ENOTSUP;
662849
return 0;
663850
}
851+
852+
long nvme_insert_tls_key(const char *keyring, const char *key_type,
853+
const char *hostnqn, const char *subsysnqn, int hmac,
854+
unsigned char *configured_key, int key_len)
855+
{
856+
return derive_nvme_keys(NULL, NULL, 0, NULL, NULL, 0);
857+
}
664858
#endif

src/nvme/linux.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,4 +205,24 @@ int nvme_gen_dhchap_key(char *hostnqn, enum nvme_hmac_alg hmac,
205205
*/
206206
long nvme_lookup_keyring(const char *keyring);
207207

208+
/**
209+
* nvme_insert_tls_key() - Derive and insert TLS key
210+
* @keyring: Keyring to use
211+
* @key_type: Type of the resulting key
212+
* @hostnqn: Host NVMe Qualified Name
213+
* @subsysnqn: Subsystem NVMe Qualified Name
214+
* @hmac: HMAC algorithm
215+
* @configured_key: Configured key data to derive the key from
216+
* @key_len: Length of @configured_key
217+
*
218+
* Derives a 'retained' TLS key as specified in NVMe TCP 1.0a and
219+
* stores it as type @key_type in the keyring specified by @keyring.
220+
*
221+
* Return: The key serial number if the key could be inserted into
222+
* the keyring or 0 with errno otherwise.
223+
*/
224+
long nvme_insert_tls_key(const char *keyring, const char *key_type,
225+
const char *hostnqn, const char *subsysnqn, int hmac,
226+
unsigned char *configured_key, int key_len);
227+
208228
#endif /* _LIBNVME_LINUX_H */

0 commit comments

Comments
 (0)