Skip to content

Commit

Permalink
fabrics: move key store operation to connect
Browse files Browse the repository at this point in the history
When the JSON parser detects a TLS key it inserts it into the keystore.
Keystore operations on the default '.nvme' keyring are privileged
operations (root) thus the parser will fail. This will fail nvme-cli
commands which are run as normal user.

Let's move the key store operations to the connect call path where we
need the right permission. A nice side benefit is that we also are able
to pass in a configured key.

Signed-off-by: Daniel Wagner <dwagner@suse.de>
  • Loading branch information
igaw committed Oct 10, 2024
1 parent 2d12b96 commit 7935bce
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 106 deletions.
78 changes: 76 additions & 2 deletions src/nvme/fabrics.c
Original file line number Diff line number Diff line change
Expand Up @@ -545,13 +545,54 @@ static bool traddr_is_hostname(nvme_root_t r, nvme_ctrl_t c)
return true;
}

static long insert_tls_key(nvme_host_t h, nvme_ctrl_t c,
const char *keyring_str, 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;
size_t key_len;
unsigned char version;
unsigned char hmac;
long key_id;

if (!hostnqn || !subsysnqn) {
nvme_msg(h->r, LOG_ERR, "Invalid NQNs (%s, %s)\n",
hostnqn, subsysnqn);
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_str, "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;
_cleanup_free_ char *keyring = NULL;
const char *tls_key;
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 +614,52 @@ static int build_options(nvme_host_t h, nvme_ctrl_t c, char **argstr)
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 = (char *)nvme_ctrl_get_keyring(c);
if (!keyring) {
char *desc, *p;

keyring_id = cfg->keyring;
desc = nvme_describe_key_serial(keyring_id);
if (desc) {
p = strstr(desc, "keyring:");
if (p)
keyring = strdup(p);
free(desc);
}
} else {
keyring_id = nvme_lookup_keyring(keyring);
keyring = strdup(keyring);
}

tls_key = nvme_ctrl_get_tls_key(c);
if (tls_key) {
key_id = insert_tls_key(h, c, keyring, 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 +701,9 @@ static int build_options(nvme_host_t h, nvme_ctrl_t c, char **argstr)
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
19 changes: 12 additions & 7 deletions src/nvme/tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -1916,10 +1916,9 @@ static char *nvme_ctrl_lookup_phy_slot(nvme_root_t r, const char *address)
static int nvme_configure_ctrl(nvme_root_t r, nvme_ctrl_t c, const char *path,
const char *name)
{
DIR *d;
_cleanup_free_ char *tls_key = NULL;
char *host_key, *ctrl_key;

_cleanup_free_ char *tls_psk = NULL;
DIR *d;

d = opendir(path);
if (!d) {
Expand Down Expand Up @@ -1963,14 +1962,20 @@ static int nvme_configure_ctrl(nvme_root_t r, nvme_ctrl_t c, const char *path,
c->dhchap_ctrl_key = ctrl_key;
}

tls_psk = nvme_get_ctrl_attr(c, "tls_key");
if (tls_psk) {
tls_key = nvme_get_ctrl_attr(c, "tls_key");
if (tls_key) {
char *endptr;
long key_id = strtol(tls_psk, &endptr, 16);
long key_id = strtol(tls_key, &endptr, 16);

if (endptr != tls_psk) {
if (endptr != tls_key) {
c->cfg.tls_key = key_id;
c->cfg.tls = true;

if (!nvme_ctrl_get_tls_key(c)) {
tls_key = nvme_describe_key_serial(c->cfg.tls_key);
if (tls_key)
nvme_ctrl_set_tls_key(c, tls_key);
}
}
}

Expand Down

0 comments on commit 7935bce

Please sign in to comment.