Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TLS keys handling #894

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
11 changes: 11 additions & 0 deletions src/libnvme.map
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
LIBNVME_1.11 {
global:
nvme_ctrl_get_keyring;
nvme_ctrl_get_tls_key;
nvme_ctrl_set_keyring;
nvme_ctrl_set_tls_key;
nvme_export_tls_key_versioned;
nvme_import_tls_key_versioned;
};


LIBNVME_1.10 {
global:
nvme_free_uri;
Expand Down
71 changes: 69 additions & 2 deletions src/nvme/fabrics.c
Original file line number Diff line number Diff line change
Expand Up @@ -545,13 +545,58 @@
return true;
}

static long insert_tls_key(nvme_host_t h, nvme_ctrl_t c,
long keyring_id, const char *encoded_key)
{
const char *hostnqn = nvme_host_get_hostnqn(h);
const char *subsysnqn = nvme_ctrl_get_subsysnqn(c);
_cleanup_free_ unsigned char *key_data = NULL;

Check failure on line 553 in src/nvme/fabrics.c

View workflow job for this annotation

GitHub Actions / checkpatch review

WARNING: Missing a blank line after declarations
unsigned char version;
unsigned char hmac;
size_t key_len;
long key_id;

if (!hostnqn || !subsysnqn) {
nvme_msg(h->r, LOG_ERR, "Invalid NQNs (%s, %s)\n",
hostnqn, subsysnqn);
return -1;
}

if (nvme_set_keyring(keyring_id) < 0) {
nvme_msg(h->r, LOG_ERR, "Failed to set keyring\n");
return -1;
}

key_data = nvme_import_tls_key_versioned(encoded_key, &version,
&hmac, &key_len);
if (!key_data) {
nvme_msg(h->r, LOG_ERR, "Failed to decode TLS Key '%s'\n",
encoded_key);
return -1;
}

key_id = __nvme_insert_tls_key_versioned(keyring_id, "psk",
hostnqn, subsysnqn,
version, hmac, key_data, key_len);
if (key_id <= 0) {
nvme_msg(h->r, LOG_ERR, "Failed to insert TLS KEY, error %d\n",
errno);
return -1;
}

return key_id;
}

static int build_options(nvme_host_t h, nvme_ctrl_t c, char **argstr)
{
struct nvme_fabrics_config *cfg = nvme_ctrl_get_config(c);
const char *transport = nvme_ctrl_get_transport(c);
const char *hostnqn, *hostid, *hostkey, *ctrlkey;
const char *tls_key, *keyring;
bool discover = false, discovery_nqn = false;
nvme_root_t r = h->r;
long keyring_id = 0;
long key_id = 0;

if (!transport) {
nvme_msg(h->r, LOG_ERR, "need a transport (-t) argument\n");
Expand All @@ -573,19 +618,41 @@
errno = ENOMEM;
return -1;
}

if (!strcmp(nvme_ctrl_get_subsysnqn(c), NVME_DISC_SUBSYS_NAME)) {
nvme_ctrl_set_discovery_ctrl(c, true);
nvme_ctrl_set_unique_discovery_ctrl(c, false);
discovery_nqn = true;
}

if (nvme_ctrl_is_discovery_ctrl(c))
discover = true;

hostnqn = nvme_host_get_hostnqn(h);
hostid = nvme_host_get_hostid(h);
hostkey = nvme_host_get_dhchap_key(h);
if (!hostkey)
hostkey = nvme_ctrl_get_dhchap_host_key(c);

ctrlkey = nvme_ctrl_get_dhchap_key(c);

keyring = nvme_ctrl_get_keyring(c);
if (keyring)
keyring_id = nvme_lookup_keyring(keyring);
else
keyring_id = cfg->keyring;

tls_key = nvme_ctrl_get_tls_key(c);
if (tls_key) {
key_id = insert_tls_key(h, c, keyring_id, tls_key);
if (key_id < 0) {
errno = ENVME_CONNECT_INVAL;
return -1;
}
} else {
key_id = cfg->tls_key;
}

if (add_argument(r, argstr, transport, transport) ||
add_argument(r, argstr, traddr,
nvme_ctrl_get_traddr(c)) ||
Expand Down Expand Up @@ -627,9 +694,9 @@
cfg->fast_io_fail_tmo, false)) ||
(strcmp(transport, "loop") &&
add_int_argument(r, argstr, tos, cfg->tos, true)) ||
add_int_argument(r, argstr, keyring, cfg->keyring, false) ||
add_int_argument(r, argstr, keyring, keyring_id, false) ||
(!strcmp(transport, "tcp") &&
add_int_argument(r, argstr, tls_key, cfg->tls_key, false)) ||
add_int_argument(r, argstr, tls_key, key_id, false)) ||
add_bool_argument(r, argstr, duplicate_connect,
cfg->duplicate_connect) ||
add_bool_argument(r, argstr, disable_sqflow,
Expand Down
122 changes: 25 additions & 97 deletions src/nvme/json.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,62 +25,10 @@
#define JSON_UPDATE_BOOL_OPTION(c, k, a, o) \
if (!strcmp(# a, k ) && !c->a) c->a = json_object_get_boolean(o);

static void json_import_nvme_tls_key(nvme_ctrl_t c, const char *keyring_str,
const char *encoded_key)
{
struct nvme_fabrics_config *cfg = nvme_ctrl_get_config(c);
const char *hostnqn = nvme_host_get_hostnqn(c->s->h);
const char *subsysnqn = nvme_ctrl_get_subsysnqn(c);
int key_len;
unsigned int hmac;
long key_id;
_cleanup_free_ unsigned char *key_data = NULL;

if (!hostnqn || !subsysnqn) {
nvme_msg(NULL, LOG_ERR, "Invalid NQNs (%s, %s)\n",
hostnqn, subsysnqn);
return;
}
key_data = nvme_import_tls_key(encoded_key, &key_len, &hmac);
if (!key_data) {
nvme_msg(NULL, LOG_ERR, "Failed to decode TLS Key '%s'\n",
encoded_key);
return;
}
key_id = nvme_insert_tls_key_versioned(keyring_str, "psk",
hostnqn, subsysnqn,
0, hmac, key_data, key_len);
if (key_id <= 0)
nvme_msg(NULL, LOG_ERR, "Failed to insert TLS KEY, error %d\n",
errno);
else {
cfg->tls_key = key_id;
cfg->tls = true;
}
}

static void json_export_nvme_tls_key(long keyring_id, long tls_key,
struct json_object *obj)
{
int key_len;
_cleanup_free_ unsigned char *key_data = NULL;

key_data = nvme_read_key(keyring_id, tls_key, &key_len);
if (key_data) {
_cleanup_free_ char *tls_str = NULL;

tls_str = nvme_export_tls_key(key_data, key_len);
if (tls_str)
json_object_object_add(obj, "tls_key",
json_object_new_string(tls_str));
}
}

static void json_update_attributes(nvme_ctrl_t c,
struct json_object *ctrl_obj)
{
struct nvme_fabrics_config *cfg = nvme_ctrl_get_config(c);
const char *keyring_str = NULL, *encoded_key = NULL;

json_object_object_foreach(ctrl_obj, key_str, val_obj) {
JSON_UPDATE_INT_OPTION(cfg, key_str,
Expand Down Expand Up @@ -120,31 +68,13 @@ static void json_update_attributes(nvme_ctrl_t c,
if (!strcmp("discovery", key_str) &&
!nvme_ctrl_is_discovery_ctrl(c))
nvme_ctrl_set_discovery_ctrl(c, true);
/*
* The JSON configuration holds the keyring description
* which needs to be converted into the keyring serial number.
*/
if (!strcmp("keyring", key_str) && cfg->keyring == 0) {
long keyring;

keyring_str = json_object_get_string(val_obj);
keyring = nvme_lookup_keyring(keyring_str);
if (keyring) {
cfg->keyring = keyring;
nvme_set_keyring(cfg->keyring);
}
}
if (!strcmp("tls_key", key_str) && cfg->tls_key == 0)
encoded_key = json_object_get_string(val_obj);
if (!strcmp("keyring", key_str))
nvme_ctrl_set_keyring(c,
json_object_get_string(val_obj));
if (!strcmp("tls_key", key_str))
nvme_ctrl_set_tls_key(c,
json_object_get_string(val_obj));
}

/*
* We might need the keyring information from the above loop,
* so we can only import the TLS key once all entries are
* processed.
*/
if (encoded_key)
json_import_nvme_tls_key(c, keyring_str, encoded_key);
}

static void json_parse_port(nvme_subsystem_t s, struct json_object *port_obj)
Expand Down Expand Up @@ -181,6 +111,12 @@ static void json_parse_port(nvme_subsystem_t s, struct json_object *port_obj)
attr_obj = json_object_object_get(port_obj, "dhchap_ctrl_key");
if (attr_obj)
nvme_ctrl_set_dhchap_key(c, json_object_get_string(attr_obj));
attr_obj = json_object_object_get(port_obj, "keyring");
if (attr_obj)
nvme_ctrl_set_keyring(c, json_object_get_string(attr_obj));
attr_obj = json_object_object_get(port_obj, "tls_key");
if (attr_obj)
nvme_ctrl_set_tls_key(c, json_object_get_string(attr_obj));
}

static void json_parse_subsys(nvme_host_t h, struct json_object *subsys_obj)
Expand Down Expand Up @@ -368,6 +304,15 @@ static void json_update_port(struct json_object *ctrl_array, nvme_ctrl_t c)
if (value)
json_object_object_add(port_obj, "dhchap_ctrl_key",
json_object_new_string(value));
JSON_BOOL_OPTION(cfg, port_obj, tls);
value = nvme_ctrl_get_keyring(c);
if (value)
json_object_object_add(port_obj, "keyring",
json_object_new_string(value));
value = nvme_ctrl_get_tls_key(c);
if (value)
json_object_object_add(port_obj, "tls_key",
json_object_new_string(value));
JSON_INT_OPTION(cfg, port_obj, nr_io_queues, 0);
JSON_INT_OPTION(cfg, port_obj, nr_write_queues, 0);
JSON_INT_OPTION(cfg, port_obj, nr_poll_queues, 0);
Expand All @@ -384,31 +329,13 @@ static void json_update_port(struct json_object *ctrl_array, nvme_ctrl_t c)
JSON_BOOL_OPTION(cfg, port_obj, disable_sqflow);
JSON_BOOL_OPTION(cfg, port_obj, hdr_digest);
JSON_BOOL_OPTION(cfg, port_obj, data_digest);
JSON_BOOL_OPTION(cfg, port_obj, tls);
JSON_BOOL_OPTION(cfg, port_obj, concat);
if (nvme_ctrl_is_persistent(c))
json_object_object_add(port_obj, "persistent",
json_object_new_boolean(true));
if (nvme_ctrl_is_discovery_ctrl(c))
json_object_object_add(port_obj, "discovery",
json_object_new_boolean(true));
/*
* Store the keyring description in the JSON config file.
*/
if (cfg->keyring) {
_cleanup_free_ char *desc =
nvme_describe_key_serial(cfg->keyring);

if (desc) {
json_object_object_add(port_obj, "keyring",
json_object_new_string(desc));
}
}
/*
* Store the TLS key in PSK interchange format
*/
if (cfg->tls_key)
json_export_nvme_tls_key(cfg->keyring, cfg->tls_key, port_obj);

json_object_array_add(ctrl_array, port_obj);
}
Expand Down Expand Up @@ -564,9 +491,10 @@ static void json_dump_ctrl(struct json_object *ctrl_array, nvme_ctrl_t c)
if (!strcmp(transport, "tcp")) {
JSON_BOOL_OPTION(cfg, ctrl_obj, tls);

if (cfg->tls_key)
json_export_nvme_tls_key(cfg->keyring, cfg->tls_key,
ctrl_obj);
value = nvme_ctrl_get_tls_key(c);
if (value)
json_object_object_add(ctrl_obj, "tls_key",
json_object_new_string(value));
}
JSON_BOOL_OPTION(cfg, ctrl_obj, concat);
if (nvme_ctrl_is_persistent(c))
Expand Down
Loading